config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

flycheck.el (508078B)


      1 ;;; flycheck.el --- On-the-fly syntax checking -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2017-2024 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 ;;             Bozhidar Batsov <bozhidar@batsov.dev>
     11 ;; URL: https://www.flycheck.org
     12 ;; Keywords: convenience, languages, tools
     13 ;; Version: 35.0-snapshot
     14 ;; Package-Requires: ((emacs "26.1"))
     15 
     16 ;; This file is not part of GNU Emacs.
     17 
     18 ;; This program is free software: you can redistribute it and/or modify
     19 ;; it under the terms of the GNU General Public License as published by
     20 ;; the Free Software Foundation, either version 3 of the License, or
     21 ;; (at your option) any later version.
     22 
     23 ;; This program is distributed in the hope that it will be useful,
     24 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     26 ;; GNU General Public License for more details.
     27 
     28 ;; You should have received a copy of the GNU General Public License
     29 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     30 
     31 ;;; Commentary:
     32 
     33 ;; On-the-fly syntax checking for GNU Emacs.
     34 ;;
     35 ;; Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs,
     36 ;; intended as replacement for the older Flymake extension which is part of GNU
     37 ;; Emacs.
     38 ;;
     39 ;; Flycheck automatically checks buffers for errors while you type, and reports
     40 ;; warnings and errors directly in the buffer and in an optional IDE-like error
     41 ;; list.
     42 ;;
     43 ;; It comes with a rich interface for custom syntax checkers and other
     44 ;; extensions, and has already many 3rd party extensions adding new features.
     45 ;;
     46 ;; Please read the online manual at https://www.flycheck.org for more
     47 ;; information.  You can open the manual directly from Emacs with `M-x
     48 ;; flycheck-manual'.
     49 ;;
     50 ;; # Setup
     51 ;;
     52 ;; Flycheck works best on Unix systems.  It does not officially support Windows,
     53 ;; but tries to maintain Windows compatibility and should generally work fine on
     54 ;; Windows, too.
     55 ;;
     56 ;; To enable Flycheck add the following to your init file:
     57 ;;
     58 ;;    (add-hook 'after-init-hook #'global-flycheck-mode)
     59 ;;
     60 ;; Flycheck will then automatically check buffers in supported languages, as
     61 ;; long as all necessary tools are present.  Use `flycheck-verify-setup' to
     62 ;; troubleshoot your Flycheck setup.
     63 
     64 ;;; Code:
     65 
     66 (eval-when-compile
     67   (require 'let-alist)      ; `let-alist'
     68   (require 'compile)        ; Compile Mode integration
     69   (require 'jka-compr)      ; To inhibit compression of temp files
     70   (require 'pcase)          ; `pcase-dolist' (`pcase' itself is autoloaded)
     71   )
     72 
     73 (require 'seq)                   ; Sequence functions
     74 (require 'subr-x)                ; Additional utilities
     75 (require 'cl-lib)                ; `cl-defstruct' and CL utilities
     76 (require 'tabulated-list)        ; To list errors
     77 (require 'easymenu)              ; Flycheck Mode menu definition
     78 (require 'rx)                    ; Regexp fanciness in `flycheck-define-checker'
     79 (require 'help-mode)             ; `define-button-type'
     80 (require 'find-func)             ; `find-function-regexp-alist'
     81 (require 'json)                  ; `flycheck-parse-json'
     82 (require 'ansi-color)            ; `flycheck-parse-with-patterns-without-color'
     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 (defvar markdown-hide-markup)                     ;
     89 (defvar markdown-fontify-code-block-default-mode) ; For rust-error-explainer
     90 (defvar markdown-fontify-code-blocks-natively)    ;
     91 
     92 ;; Tell the byte compiler about autoloaded functions from packages
     93 (declare-function pkg-info-version-info "pkg-info" (package))
     94 
     95 
     96 ;;; Customization
     97 (defgroup flycheck nil
     98   "Modern on-the-fly syntax checking for GNU Emacs."
     99   :prefix "flycheck-"
    100   :group 'tools
    101   :link '(url-link :tag "Website" "https://www.flycheck.org")
    102   :link '(url-link :tag "Github" "https://github.com/flycheck/flycheck"))
    103 
    104 (defgroup flycheck-config-files nil
    105   "Configuration files for on-the-fly syntax checkers."
    106   :prefix "flycheck-"
    107   :group 'flycheck)
    108 
    109 (defgroup flycheck-options nil
    110   "Options for on-the-fly syntax checkers."
    111   :prefix "flycheck-"
    112   :group 'flycheck)
    113 
    114 (defgroup flycheck-executables nil
    115   "Executables of syntax checkers."
    116   :prefix "flycheck-"
    117   :group 'flycheck)
    118 
    119 (defgroup flycheck-faces nil
    120   "Faces used by on-the-fly syntax checking."
    121   :prefix "flycheck-"
    122   :group 'flycheck)
    123 
    124 (defcustom flycheck-checkers
    125   '(ada-gnat
    126     asciidoctor
    127     asciidoc
    128     awk-gawk
    129     bazel-build-buildifier
    130     bazel-module-buildifier
    131     bazel-starlark-buildifier
    132     bazel-workspace-buildifier
    133     c/c++-clang
    134     c/c++-gcc
    135     c/c++-cppcheck
    136     cfengine
    137     coffee
    138     coffee-coffeelint
    139     css-csslint
    140     css-stylelint
    141     cuda-nvcc
    142     cwl
    143     d-dmd
    144     dockerfile-hadolint
    145     elixir-credo
    146     emacs-lisp
    147     emacs-lisp-checkdoc
    148     ember-template
    149     erlang-rebar3
    150     erlang
    151     eruby-erubis
    152     eruby-ruumba
    153     fortran-gfortran
    154     go-gofmt
    155     go-vet
    156     go-build
    157     go-test
    158     go-errcheck
    159     go-unconvert
    160     go-staticcheck
    161     groovy
    162     haml
    163     haml-lint
    164     handlebars
    165     haskell-stack-ghc
    166     haskell-ghc
    167     haskell-hlint
    168     html-tidy
    169     javascript-eslint
    170     javascript-jshint
    171     javascript-standard
    172     json-jsonlint
    173     json-python-json
    174     json-jq
    175     jsonnet
    176     less
    177     less-stylelint
    178     llvm-llc
    179     lua-luacheck
    180     lua
    181     markdown-markdownlint-cli
    182     markdown-mdl
    183     markdown-pymarkdown
    184     nix
    185     nix-linter
    186     opam
    187     perl
    188     perl-perlcritic
    189     php
    190     php-phpmd
    191     php-phpcs
    192     php-phpcs-changed
    193     processing
    194     proselint
    195     protobuf-protoc
    196     protobuf-prototool
    197     pug
    198     puppet-parser
    199     puppet-lint
    200     python-flake8
    201     python-ruff
    202     python-pylint
    203     python-pycompile
    204     python-pyright
    205     python-mypy
    206     r-lintr
    207     r
    208     racket
    209     rpm-rpmlint
    210     rst-sphinx
    211     rst
    212     ruby-rubocop
    213     ruby-chef-cookstyle
    214     ruby-standard
    215     ruby-reek
    216     ruby
    217     ruby-jruby
    218     rust-cargo
    219     rust
    220     rust-clippy
    221     scala
    222     scala-scalastyle
    223     scheme-chicken
    224     scss-lint
    225     sass-stylelint
    226     scss-stylelint
    227     sass/scss-sass-lint
    228     sass
    229     scss
    230     sh-bash
    231     sh-posix-dash
    232     sh-posix-bash
    233     sh-zsh
    234     sh-shellcheck
    235     slim
    236     slim-lint
    237     sql-sqlint
    238     statix
    239     systemd-analyze
    240     tcl-nagelfar
    241     terraform
    242     terraform-tflint
    243     tex-chktex
    244     tex-lacheck
    245     texinfo
    246     textlint
    247     typescript-tslint
    248     verilog-verilator
    249     vhdl-ghdl
    250     xml-xmlstarlet
    251     xml-xmllint
    252     yaml-actionlint
    253     yaml-jsyaml
    254     yaml-ruby
    255     yaml-yamllint)
    256   "Syntax checkers available for automatic selection.
    257 
    258 A list of Flycheck syntax checkers to choose from when syntax
    259 checking a buffer.  Flycheck will automatically select a suitable
    260 syntax checker from this list, unless `flycheck-checker' is set,
    261 either directly or with `flycheck-select-checker'.
    262 
    263 You should not need to change this variable normally.  In order
    264 to disable syntax checkers, please use
    265 `flycheck-disabled-checkers'.  This variable is intended for 3rd
    266 party extensions to tell Flycheck about new syntax checkers.
    267 
    268 Syntax checkers in this list must be defined with
    269 `flycheck-define-checker'."
    270   :group 'flycheck
    271   :type '(repeat (symbol :tag "Checker"))
    272   :risky t)
    273 
    274 (defcustom flycheck-disabled-checkers nil
    275   "Syntax checkers excluded from automatic selection.
    276 
    277 A list of Flycheck syntax checkers to exclude from automatic
    278 selection.  Flycheck will never automatically select a syntax
    279 checker in this list, regardless of the value of
    280 `flycheck-checkers'.
    281 
    282 However, syntax checkers in this list are still available for
    283 manual selection with `flycheck-select-checker'.
    284 
    285 Use this variable to disable syntax checkers, instead of removing
    286 the syntax checkers from `flycheck-checkers'.  You may also use
    287 this option as a file or directory local variable to disable
    288 specific checkers in individual files and directories
    289 respectively."
    290   :group 'flycheck
    291   :type '(repeat (symbol :tag "Checker"))
    292   :package-version '(flycheck . "0.16")
    293   :safe #'flycheck-symbol-list-p)
    294 (make-variable-buffer-local 'flycheck-disabled-checkers)
    295 
    296 (defvar-local flycheck--automatically-disabled-checkers nil
    297   "List of syntax checkers automatically disabled for this buffer.
    298 
    299 A checker can be automatically disabled in two cases:
    300 
    301 1. Its `:enabled' predicate returned false.
    302 2. It returned too many errors (see `flycheck-checker-error-threshold').
    303 
    304 To trigger a reverification from Emacs Lisp code, do not modify
    305 this variable: use `flycheck-reset-enabled-checker'.")
    306 
    307 (defvar-local flycheck-checker nil
    308   "Syntax checker to use for the current buffer.
    309 
    310 If unset or nil, automatically select a suitable syntax checker
    311 from `flycheck-checkers' on every syntax check.
    312 
    313 If set to a syntax checker only use this syntax checker and never
    314 select one from `flycheck-checkers' automatically.  The syntax
    315 checker is used regardless of whether it is contained in
    316 `flycheck-checkers' or `flycheck-disabled-checkers'.  If the
    317 syntax checker is unusable in the current buffer an error is
    318 signaled.
    319 
    320 A syntax checker assigned to this variable must be defined with
    321 `flycheck-define-checker'.
    322 
    323 Use the command `flycheck-select-checker' to select a syntax
    324 checker for the current buffer, or set this variable as file
    325 local variable to always use a specific syntax checker for a
    326 file.  See Info Node `(Emacs)Specifying File Variables' for more
    327 information about file variables.")
    328 (put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p)
    329 
    330 (defcustom flycheck-locate-config-file-functions nil
    331   "Functions to locate syntax checker configuration files.
    332 
    333 Each function in this hook must accept two arguments: The value
    334 of the configuration file variable, and the syntax checker
    335 symbol.  It must return either a string with an absolute path to
    336 the configuration file, or nil, if it cannot locate the
    337 configuration file.
    338 
    339 The functions in this hook are called in order of appearance, until a
    340 function returns non-nil.  The configuration file returned by that
    341 function is then given to the syntax checker if it exists.
    342 
    343 This variable is an abnormal hook.  See Info
    344 node `(elisp)Hooks'."
    345   :group 'flycheck
    346   :type 'hook
    347   :risky t)
    348 
    349 (defcustom flycheck-checker-error-threshold 400
    350   "Maximum errors allowed per syntax checker.
    351 
    352 The value of this variable is either an integer denoting the
    353 maximum number of errors per syntax checker and buffer, or nil to
    354 not limit the errors reported from a syntax checker.
    355 
    356 If this variable is a number and a syntax checker reports more
    357 errors than the value of this variable, its errors are not
    358 discarded, and not highlighted in the buffer or available in the
    359 error list.  The affected syntax checker is also disabled for
    360 future syntax checks of the buffer."
    361   :group 'flycheck
    362   :type '(choice (const :tag "Do not limit reported errors" nil)
    363                  (integer :tag "Maximum number of errors"))
    364   :risky t
    365   :package-version '(flycheck . "0.22"))
    366 
    367 (defcustom flycheck-process-error-functions nil
    368   "Functions to process errors.
    369 
    370 Each function in this hook must accept a single argument: A
    371 Flycheck error to process.
    372 
    373 All functions in this hook are called in order of appearance,
    374 until a function returns non-nil.  Thus, a function in this hook
    375 may return nil, to allow for further processing of the error, or
    376 any non-nil value, to indicate that the error was fully processed
    377 and inhibit any further processing.
    378 
    379 The functions are called for each newly parsed error immediately
    380 after the corresponding syntax checker finished.  At this stage,
    381 the overlays from the previous syntax checks are still present,
    382 and there may be further syntax checkers in the chain.
    383 
    384 This variable is an abnormal hook.  See Info
    385 node `(elisp)Hooks'."
    386   :group 'flycheck
    387   :type 'hook
    388   :package-version '(flycheck . "0.13")
    389   :risky t)
    390 
    391 (defcustom flycheck-auto-display-errors-after-checking t
    392   "Whether to automatically display errors at the current point after checking.
    393 
    394 When being set to `nil', it will prevent Flycheck from automatically displaying
    395 error messages. This setting is useful when Flycheck is used together with
    396 `flycheck-posframe', to prevent `flycheck-posframe' from repeatedly displaying
    397 errors at point."
    398   :group 'flycheck
    399   :type 'boolean
    400   :package-version '(flycheck . "35")
    401   :safe #'booleanp)
    402 
    403 (defcustom flycheck-display-errors-delay 0.9
    404   "Delay in seconds before displaying errors at point.
    405 
    406 Use floating point numbers to express fractions of seconds."
    407   :group 'flycheck
    408   :type 'number
    409   :package-version '(flycheck . "0.15")
    410   :safe #'numberp)
    411 
    412 (defcustom flycheck-display-errors-function #'flycheck-display-error-messages
    413   "Function to display error messages.
    414 
    415 If set to a function, call the function with the list of errors
    416 to display as single argument.  Each error is an instance of the
    417 `flycheck-error' struct.
    418 
    419 If set to nil, do not display errors at all."
    420   :group 'flycheck
    421   :type '(choice (const :tag "Display error messages"
    422                         flycheck-display-error-messages)
    423                  (const :tag "Display error messages only if no error list"
    424                         flycheck-display-error-messages-unless-error-list)
    425                  (function :tag "Error display function"))
    426   :package-version '(flycheck . "0.13")
    427   :risky t)
    428 
    429 (defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages
    430   "Function to compute the contents of the error tooltips.
    431 
    432 If set to a function, call the function with the list of errors
    433 to display as single argument.  Each error is an instance of the
    434 `flycheck-error' struct.  The function is used to set the
    435 help-echo property of flycheck error overlays.  It should return
    436 a string, which is displayed when the user hovers over an error
    437 or presses \\[display-local-help].
    438 
    439 If set to nil, do not show error tooltips."
    440   :group 'flycheck
    441   :type '(choice (const :tag "Concatenate error messages to form a tooltip"
    442                         flycheck-help-echo-all-error-messages)
    443                  (function :tag "Help echo function"))
    444   :package-version '(flycheck . "0.25")
    445   :risky t)
    446 
    447 (defcustom flycheck-command-wrapper-function #'identity
    448   "Function to modify checker commands before execution.
    449 
    450 The value of this option is a function which is given a list
    451 containing the full command of a syntax checker after
    452 substitution through `flycheck-substitute-argument' but before
    453 execution.  The function may return a new command for Flycheck to
    454 execute.
    455 
    456 The default value is `identity' which does not change the
    457 command.  You may provide your own function to run Flycheck
    458 commands through `bundle exec', `nix-shell' or similar wrappers."
    459   :group 'flycheck
    460   :type '(choice (const :tag "Do not modify commands" identity)
    461                  (function :tag "Modify command with a custom function"))
    462   :package-version '(flycheck . "0.25")
    463   :risky t)
    464 
    465 (defcustom flycheck-executable-find #'flycheck-default-executable-find
    466   "Function to search for executables.
    467 
    468 The value of this option is a function which is given the name or
    469 path of an executable and shall return the full path to the
    470 executable, or nil if the executable does not exit.
    471 
    472 The default is `flycheck-default-executable-find', which searches
    473 variable `exec-path' when given a command name, and resolves
    474 paths to absolute ones.  You can customize this option to search
    475 for checkers in other environments such as bundle or NixOS
    476 sandboxes."
    477   :group 'flycheck
    478   :type '(choice
    479           (const :tag "Search executables in `exec-path'"
    480                  flycheck-default-executable-find)
    481           (function :tag "Search executables with a custom function"))
    482   :package-version '(flycheck . "32")
    483   :risky t)
    484 
    485 (defun flycheck-default-executable-find (executable)
    486   "Resolve EXECUTABLE to a full path.
    487 
    488 Like `executable-find', but supports relative paths.
    489 
    490 Attempts invoking `executable-find' first; if that returns nil,
    491 and EXECUTABLE contains a directory component, expands to a full
    492 path and tries invoking `executable-find' again."
    493   ;; file-name-directory returns non-nil iff the given path has a
    494   ;; directory component.
    495   (or
    496    (executable-find executable)
    497    (when (file-name-directory executable)
    498      (executable-find (expand-file-name executable)))))
    499 
    500 (defcustom flycheck-indication-mode 'left-fringe
    501   "The indication mode for Flycheck errors.
    502 
    503 This variable controls how Flycheck indicates errors in buffers.
    504 May be `left-fringe', `right-fringe', `left-margin',
    505 `right-margin', or nil.
    506 
    507 If set to `left-fringe' or `right-fringe', indicate errors via
    508 icons in the left and right fringe respectively.  If set to
    509 `left-margin' or `right-margin', use the margins instead.
    510 
    511 If set to nil, do not indicate errors and warnings, but just
    512 highlight them according to `flycheck-highlighting-mode'."
    513   :group 'flycheck
    514   :type '(choice (const :tag "Indicate in the left fringe" left-fringe)
    515                  (const :tag "Indicate in the right fringe" right-fringe)
    516                  (const :tag "Indicate in the left margin" left-margin)
    517                  (const :tag "Indicate in the right margin" right-margin)
    518                  (const :tag "Do not indicate" nil))
    519   :safe #'symbolp)
    520 
    521 (defcustom flycheck-highlighting-mode 'symbols
    522   "The highlighting mode for Flycheck errors and warnings.
    523 
    524 The highlighting mode controls how Flycheck highlights errors in
    525 buffers when a checker only reports the starting position of an
    526 error.  The following modes are known:
    527 
    528 `columns'
    529      Highlight a single character.  If the error does not have a column,
    530      highlight the whole line.
    531 
    532 `symbols'
    533      Highlight a full symbol if there is any, otherwise behave like `columns'.
    534      This is the default.
    535 
    536 `sexps'
    537      Highlight a full expression, if there is any, otherwise behave like
    538      `columns'.  Note that this mode can be *very* slow in some major modes.
    539 
    540 `lines'
    541      Highlight the whole line.
    542 
    543 nil
    544      Do not highlight errors at all.  However, errors will still
    545      be reported in the mode line and in error message popups,
    546      and indicated according to `flycheck-indication-mode'."
    547   :group 'flycheck
    548   :type '(choice (const :tag "Highlight columns only" columns)
    549                  (const :tag "Highlight symbols" symbols)
    550                  (const :tag "Highlight expressions" sexps)
    551                  (const :tag "Highlight whole lines" lines)
    552                  (const :tag "Do not highlight errors" nil))
    553   :package-version '(flycheck . "0.14")
    554   :safe #'symbolp)
    555 
    556 (defvar flycheck-current-errors)
    557 (defun flycheck-refresh-fringes-and-margins ()
    558   "Refresh fringes and margins of all windows displaying the current buffer.
    559 
    560 If any errors are currently shown, launch a new check, to adjust
    561 to a potential new indication mode."
    562   (dolist (win (get-buffer-window-list))
    563     (set-window-margins win left-margin-width right-margin-width)
    564     (set-window-fringes win left-fringe-width right-fringe-width))
    565   (when flycheck-current-errors
    566     (flycheck-buffer)))
    567 
    568 (defun flycheck-set-indication-mode (&optional mode)
    569   "Set `flycheck-indication-mode' to MODE and adjust margins and fringes.
    570 
    571 When MODE is nil, adjust window parameters without changing the
    572 mode.  This function can be useful as a `flycheck-mode-hook',
    573 especially if you use margins only in Flycheck buffers.
    574 
    575 When MODE is `left-margin', the left fringe is reduced to 1 pixel
    576 to save space."
    577   (interactive (list (intern (completing-read
    578                               "Mode: " '("left-fringe" "right-fringe"
    579                                          "left-margin" "right-margin")
    580                               nil t nil nil
    581                               (prin1-to-string flycheck-indication-mode)))))
    582   (setq mode (or mode flycheck-indication-mode))
    583   (pcase mode
    584     ((or `left-fringe `right-fringe)
    585      (setq left-fringe-width 8 right-fringe-width 8
    586            left-margin-width 0 right-margin-width 0))
    587     (`left-margin
    588      (setq left-fringe-width 1 right-fringe-width 8
    589            left-margin-width 1 right-margin-width 0))
    590     (`right-margin
    591      (setq left-fringe-width 8 right-fringe-width 8
    592            left-margin-width 0 right-margin-width 1))
    593     (_ (user-error "Invalid indication mode")))
    594   (setq-local flycheck-indication-mode mode)
    595   (flycheck-refresh-fringes-and-margins))
    596 
    597 (define-widget 'flycheck-highlighting-style 'lazy
    598   "A value for `flycheck-highlighting-style'."
    599   :offset 2
    600   :format "%t: Use %v"
    601   :type '(choice
    602           :format "%[Value Menu%] %v"
    603           (const :tag "no highlighting" nil)
    604           (const :tag "a face indicating the error level" level-face)
    605           (list :tag "a pair of delimiters"
    606                 (const :format "" delimiters)
    607                 (string :tag "Before")
    608                 (string :tag "After"))
    609           (list :tag "a conditional mix of styles"
    610                 (const :format "" conditional)
    611                 (integer :tag "Up to this many lines")
    612                 (flycheck-highlighting-style :format "Use %v")
    613                 (flycheck-highlighting-style :format "Otherwise, use %v"))))
    614 
    615 (defun flycheck--make-highlighting-delimiter (char)
    616   "Make a highlighting bracket symbol by repeating CHAR twice."
    617   (compose-chars ?\s
    618                  ;; '(Bl . Br) ?\s
    619                  '(Bc Br 30 0) char
    620                  '(Bc Bl -30 0) char))
    621 
    622 (defcustom flycheck-highlighting-style
    623   `(conditional 4 level-face (delimiters "" ""))
    624   "The highlighting style for Flycheck errors and warnings.
    625 
    626 The highlighting style controls how Flycheck highlights error
    627 regions in buffers.  The following styles are supported:
    628 
    629 nil
    630      Do not highlight errors.  Same as setting
    631      `flycheck-highlighting-mode' to nil.
    632 
    633 `level-face'
    634      Chose a face depending on the severity of the error, and
    635      apply it to the whole error text.  See also the
    636      `flycheck-define-error-level' and `flycheck-error',
    637      `flycheck-warning', and `flycheck-info' faces.
    638 
    639 \(`delimiters' BEFORE AFTER)
    640      Draw delimiters on each side of the error.  BEFORE and AFTER
    641      indicate which delimiters to use.  If they are strings, they
    642      are used as-is.  If they are characters, they are repeated
    643      twice and composed into a single character.  Delimiters use
    644      the fringe face corresponding to the severity of each error,
    645      as well as the `flycheck-error-delimiter' face.  Delimited
    646      text has the `flycheck-delimited-error' face.
    647 
    648 \(`conditional' NLINES S1 S2)
    649      Use style S1 for errors spanning up to NLINES lines, and
    650      style S2 otherwise.
    651 
    652 See also `flycheck-highlighting-mode' and
    653 `flycheck-indication-mode'."
    654   :group 'flycheck
    655   :type 'flycheck-highlighting-style
    656   :package-version '(flycheck . "32")
    657   :safe t)
    658 
    659 (defcustom flycheck-check-syntax-automatically '(save
    660                                                  idle-change
    661                                                  new-line
    662                                                  mode-enabled)
    663   "When Flycheck should check syntax automatically.
    664 
    665 This variable is a list of events that may trigger syntax checks.
    666 The following events are known:
    667 
    668 `save'
    669      Check syntax immediately after the buffer was saved.
    670 
    671 `idle-change'
    672      Check syntax a short time (see `flycheck-idle-change-delay')
    673      after the last change to the buffer.
    674 
    675 `idle-buffer-switch'
    676      Check syntax a short time (see `flycheck-idle-buffer-switch-delay')
    677      after the user switches to a buffer.
    678 
    679 `new-line'
    680      Check syntax immediately after a new line was inserted into
    681      the buffer.
    682 
    683 `mode-enabled'
    684      Check syntax immediately when variable `flycheck-mode' is
    685      non-nil.
    686 
    687 Flycheck performs a syntax checks only on events, which are
    688 contained in this list.  For instance, if the value of this
    689 variable is `(mode-enabled save)', Flycheck will only check if
    690 the mode is enabled or the buffer was saved, but never after
    691 changes to the buffer contents.
    692 
    693 If nil, never check syntax automatically.  In this case, use
    694 `flycheck-buffer' to start a syntax check manually."
    695   :group 'flycheck
    696   :type '(set (const :tag "After the buffer was saved" save)
    697               (const :tag "After the buffer was changed and idle" idle-change)
    698               (const
    699                :tag "After switching the current buffer" idle-buffer-switch)
    700               (const :tag "After a new line was inserted" new-line)
    701               (const :tag "After `flycheck-mode' was enabled" mode-enabled))
    702   :package-version '(flycheck . "0.12")
    703   :safe #'flycheck-symbol-list-p)
    704 
    705 (defcustom flycheck-idle-change-delay 0.5
    706   "How many seconds to wait after a change before checking syntax.
    707 
    708 After the buffer was changed, Flycheck will wait as many seconds
    709 as the value of this variable before starting a syntax check.  If
    710 the buffer is modified during this time, Flycheck will wait
    711 again.
    712 
    713 This variable has no effect, if `idle-change' is not contained in
    714 `flycheck-check-syntax-automatically'."
    715   :group 'flycheck
    716   :type 'number
    717   :package-version '(flycheck . "0.13")
    718   :safe #'numberp)
    719 
    720 (defcustom flycheck-idle-buffer-switch-delay 0.5
    721   "How many seconds to wait after switching buffers before checking syntax.
    722 
    723 After the user switches to a new buffer, Flycheck will wait as
    724 many seconds as the value of this variable before starting a
    725 syntax check.  If the user switches to another buffer during this
    726 time, whether a syntax check is still performed depends on the
    727 value of `flycheck-buffer-switch-check-intermediate-buffers'.
    728 
    729 This variable has no effect if `idle-buffer-switch' is not
    730 contained in `flycheck-check-syntax-automatically'."
    731   :group 'flycheck
    732   :type 'number
    733   :package-version '(flycheck . "32")
    734   :safe #'numberp)
    735 
    736 (defcustom flycheck-buffer-switch-check-intermediate-buffers nil
    737   "Whether to check syntax in a buffer you only visit briefly.
    738 
    739 If nil, then when you switch to a buffer but switch to another
    740 buffer before the syntax check is performed, then the check is
    741 canceled.  If non-nil, then syntax checks due to switching
    742 buffers are always performed.  This only affects buffer switches
    743 that happen less than `flycheck-idle-buffer-switch-delay' seconds
    744 apart.
    745 
    746 This variable has no effect if `idle-buffer-switch' is not
    747 contained in `flycheck-check-syntax-automatically'."
    748   :group 'flycheck
    749   :type 'boolean
    750   :package-version '(flycheck . "32")
    751   :safe #'booleanp)
    752 
    753 (defcustom flycheck-standard-error-navigation t
    754   "Whether to support error navigation with `next-error'.
    755 
    756 If non-nil, enable navigation of Flycheck errors with
    757 `next-error', `previous-error' and `first-error'.  Otherwise,
    758 these functions just navigate errors from compilation modes.
    759 
    760 Flycheck error navigation with `flycheck-next-error',
    761 `flycheck-previous-error' and `flycheck-first-error' is always
    762 enabled, regardless of the value of this variable.
    763 
    764 Note that this setting only takes effect when variable
    765 `flycheck-mode' is non-nil.  Changing it will not affect buffers
    766 where variable `flycheck-mode' is already non-nil."
    767   :group 'flycheck
    768   :type 'boolean
    769   :package-version '(flycheck . "0.15")
    770   :safe #'booleanp)
    771 
    772 (define-widget 'flycheck-minimum-level 'lazy
    773   "A radio-type choice of minimum error levels.
    774 
    775 See `flycheck-navigation-minimum-level' and
    776 `flycheck-error-list-minimum-level'."
    777   :type '(radio (const :tag "All locations" nil)
    778                 (const :tag "Informational messages" info)
    779                 (const :tag "Warnings" warning)
    780                 (const :tag "Errors" error)
    781                 (symbol :tag "Custom error level")))
    782 
    783 (defcustom flycheck-navigation-minimum-level nil
    784   "The minimum level of errors to navigate.
    785 
    786 If set to an error level, only navigate errors whose error level
    787 is at least as severe as this one.  If nil, navigate all errors."
    788   :group 'flycheck
    789   :type 'flycheck-minimum-level
    790   :safe #'flycheck-error-level-p
    791   :package-version '(flycheck . "0.21"))
    792 
    793 (defcustom flycheck-error-list-minimum-level nil
    794   "The minimum level of errors to display in the error list.
    795 
    796 If set to an error level, only display errors whose error level
    797 is at least as severe as this one in the error list.  If nil,
    798 display all errors.
    799 
    800 This is the default level, used when the error list is opened.
    801 You can temporarily change the level using
    802 \\[flycheck-error-list-set-filter], or reset it to this value
    803 using \\[flycheck-error-list-reset-filter]."
    804   :group 'flycheck
    805   :type 'flycheck-minimum-level
    806   :safe #'flycheck-error-level-p
    807   :package-version '(flycheck . "0.24"))
    808 
    809 (defcustom flycheck-relevant-error-other-file-minimum-level 'error
    810   "The minimum level of errors from other files to display in this buffer.
    811 
    812 If set to an error level, only display errors from other files
    813 whose error level is at least as severe as this one.  If nil,
    814 display all errors from other files."
    815   :group 'flycheck
    816   :type 'flycheck-minimum-level
    817   :safe #'flycheck-error-level-p
    818   :package-version '(flycheck . "32"))
    819 
    820 (defcustom flycheck-relevant-error-other-file-show t
    821   "Whether to show errors from other files."
    822   :group 'flycheck
    823   :type 'boolean
    824   :package-version '(flycheck . "32")
    825   :safe #'booleanp)
    826 
    827 (defcustom flycheck-completing-read-function #'completing-read
    828   "Function to read from minibuffer with completion.
    829 
    830 The function must be compatible to the built-in `completing-read'
    831 function."
    832   :group 'flycheck
    833   :type '(choice (const :tag "Default" completing-read)
    834                  (const :tag "IDO" ido-completing-read)
    835                  (function :tag "Custom function"))
    836   :risky t
    837   :package-version '(flycheck . "26"))
    838 
    839 (defcustom flycheck-temp-prefix "flycheck"
    840   "Prefix for temporary files created by Flycheck."
    841   :group 'flycheck
    842   :type 'string
    843   :package-version '(flycheck . "0.19")
    844   :risky t)
    845 
    846 (defcustom flycheck-mode-hook nil
    847   "Hooks to run after command `flycheck-mode' is toggled."
    848   :group 'flycheck
    849   :type 'hook
    850   :risky t)
    851 
    852 (defcustom flycheck-after-syntax-check-hook nil
    853   "Functions to run after each syntax check.
    854 
    855 This hook is run after a syntax check was finished.
    856 
    857 At this point, *all* chained checkers were run, and all errors
    858 were parsed, highlighted and reported.  The variable
    859 `flycheck-current-errors' contains all errors from all syntax
    860 checkers run during the syntax check, so you can apply any error
    861 analysis functions.
    862 
    863 Note that this hook does *not* run after each individual syntax
    864 checker in the syntax checker chain, but only after the *last
    865 checker*.
    866 
    867 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    868   :group 'flycheck
    869   :type 'hook
    870   :risky t)
    871 
    872 (defcustom flycheck-before-syntax-check-hook nil
    873   "Functions to run before each syntax check.
    874 
    875 This hook is run right before a syntax check starts.
    876 
    877 Error information from the previous syntax check is *not*
    878 cleared before this hook runs.
    879 
    880 Note that this hook does *not* run before each individual syntax
    881 checker in the syntax checker chain, but only before the *first
    882 checker*.
    883 
    884 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    885   :group 'flycheck
    886   :type 'hook
    887   :risky t)
    888 
    889 (defcustom flycheck-syntax-check-failed-hook nil
    890   "Functions to run if a syntax check failed.
    891 
    892 This hook is run whenever an error occurs during Flycheck's
    893 internal processing.  No information about the error is given to
    894 this hook.
    895 
    896 You should use this hook to conduct additional cleanup actions
    897 when Flycheck failed.
    898 
    899 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    900   :group 'flycheck
    901   :type 'hook
    902   :risky t)
    903 
    904 (defcustom flycheck-status-changed-functions nil
    905   "Functions to run if the Flycheck status changed.
    906 
    907 This hook is run whenever the status of Flycheck changes.  Each
    908 hook function takes the status symbol as single argument, as
    909 given to `flycheck-report-status', which see.
    910 
    911 This variable is an abnormal hook.  See Info
    912 node `(elisp)Hooks'."
    913   :group 'flycheck
    914   :type 'hook
    915   :risky t
    916   :package-version '(flycheck . "0.20"))
    917 
    918 (defcustom flycheck-error-list-after-refresh-hook nil
    919   "Functions to run after the error list was refreshed.
    920 
    921 This hook is run whenever the error list is refreshed.
    922 
    923 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    924   :group 'flycheck
    925   :type 'hook
    926   :risky t
    927   :package-version '(flycheck . "0.21"))
    928 
    929 (defface flycheck-error-delimiter
    930   `((t))
    931   "Flycheck face for errors spanning multiple lines.
    932 
    933 See `flycheck-highlighting-style' for details on when this face
    934 is used."
    935   :package-version '(flycheck . "32")
    936   :group 'flycheck-faces)
    937 
    938 (defface flycheck-delimited-error
    939   `((t))
    940   "Flycheck face for errors spanning multiple lines.
    941 
    942 See `flycheck-highlighting-style' for details on when this face
    943 is used."
    944   :package-version '(flycheck . "32")
    945   :group 'flycheck-faces)
    946 
    947 (defface flycheck-error
    948   '((((supports :underline (:style wave)))
    949      :underline (:style wave :color "Red1"))
    950     (t
    951      :underline t :inherit error))
    952   "Flycheck face for errors."
    953   :package-version '(flycheck . "0.13")
    954   :group 'flycheck-faces)
    955 
    956 (defface flycheck-warning
    957   '((((supports :underline (:style wave)))
    958      :underline (:style wave :color "DarkOrange"))
    959     (t
    960      :underline t :inherit warning))
    961   "Flycheck face for warnings."
    962   :package-version '(flycheck . "0.13")
    963   :group 'flycheck-faces)
    964 
    965 (defface flycheck-info
    966   '((((supports :underline (:style wave)))
    967      :underline (:style wave :color "ForestGreen"))
    968     (t
    969      :underline t :inherit success))
    970   "Flycheck face for informational messages."
    971   :package-version '(flycheck . "0.15")
    972   :group 'flycheck-faces)
    973 
    974 (defface flycheck-fringe-error
    975   '((t :inherit error))
    976   "Flycheck face for fringe error indicators."
    977   :package-version '(flycheck . "0.13")
    978   :group 'flycheck-faces)
    979 
    980 (defface flycheck-fringe-warning
    981   '((t :inherit warning))
    982   "Flycheck face for fringe warning indicators."
    983   :package-version '(flycheck . "0.13")
    984   :group 'flycheck-faces)
    985 
    986 (defface flycheck-fringe-info
    987   ;; Semantically `success' is probably not the right face, but it looks nice as
    988   ;; a base face
    989   '((t :inherit success))
    990   "Flycheck face for fringe info indicators."
    991   :package-version '(flycheck . "0.15")
    992   :group 'flycheck-faces)
    993 
    994 (defface flycheck-error-list-error
    995   '((t :inherit error))
    996   "Flycheck face for error messages in the error list."
    997   :package-version '(flycheck . "0.16")
    998   :group 'flycheck-faces)
    999 
   1000 (defface flycheck-error-list-warning
   1001   '((t :inherit warning))
   1002   "Flycheck face for warning messages in the error list."
   1003   :package-version '(flycheck . "0.16")
   1004   :group 'flycheck-faces)
   1005 
   1006 (defface flycheck-error-list-info
   1007   '((t :inherit success))
   1008   "Flycheck face for info messages in the error list."
   1009   :package-version '(flycheck . "0.16")
   1010   :group 'flycheck-faces)
   1011 
   1012 (defface flycheck-error-list-line-number
   1013   '((t))
   1014   "Face for line numbers in the error list."
   1015   :group 'flycheck-faces
   1016   :package-version '(flycheck . "0.16"))
   1017 
   1018 (defface flycheck-error-list-column-number
   1019   '((t))
   1020   "Face for line numbers in the error list."
   1021   :group 'flycheck-faces
   1022   :package-version '(flycheck . "0.16"))
   1023 
   1024 (defface flycheck-error-list-filename
   1025   '((t :inherit mode-line-buffer-id :bold nil))
   1026   "Face for filenames in the error list."
   1027   :group 'flycheck-faces
   1028   :package-version '(flycheck . "32"))
   1029 
   1030 (defface flycheck-error-list-id
   1031   '((t :inherit font-lock-type-face))
   1032   "Face for the error ID in the error list."
   1033   :group 'flycheck-faces
   1034   :package-version '(flycheck . "0.22"))
   1035 
   1036 (defface flycheck-error-list-id-with-explainer
   1037   '((t :inherit flycheck-error-list-id
   1038        :box (:style released-button)))
   1039   "Face for the error ID in the error list, for errors that have an explainer."
   1040   :group 'flycheck-faces
   1041   :package-version '(flycheck . "30"))
   1042 
   1043 (defface flycheck-error-list-checker-name
   1044   '((t :inherit font-lock-function-name-face))
   1045   "Face for the syntax checker name in the error list."
   1046   :group 'flycheck-faces
   1047   :package-version '(flycheck . "0.21"))
   1048 
   1049 (defface flycheck-error-list-error-message
   1050   '((t))
   1051   "Face for the error message in the error list."
   1052   :group 'flycheck-faces
   1053   :package-version '(flycheck . "33"))
   1054 
   1055 (defface flycheck-error-list-highlight
   1056   '((t :bold t))
   1057   "Flycheck face to highlight errors in the error list."
   1058   :package-version '(flycheck . "0.15")
   1059   :group 'flycheck-faces)
   1060 
   1061 (defface flycheck-verify-select-checker
   1062   '((t :box (:style released-button)))
   1063   "Flycheck face for the `select' button in the verify setup buffer."
   1064   :package-version '(flycheck . "32")
   1065   :group 'flycheck-faces)
   1066 
   1067 (defvar flycheck-command-map
   1068   (let ((map (make-sparse-keymap)))
   1069     (define-key map "c"         #'flycheck-buffer)
   1070     (define-key map "C"         #'flycheck-clear)
   1071     (define-key map (kbd "C-c") #'flycheck-compile)
   1072     (define-key map "n"         #'flycheck-next-error)
   1073     (define-key map "p"         #'flycheck-previous-error)
   1074     (define-key map "l"         #'flycheck-list-errors)
   1075     (define-key map (kbd "C-w") #'flycheck-copy-errors-as-kill)
   1076     (define-key map "s"         #'flycheck-select-checker)
   1077     (define-key map "?"         #'flycheck-describe-checker)
   1078     (define-key map "h"         #'flycheck-display-error-at-point)
   1079     (define-key map "e"         #'flycheck-explain-error-at-point)
   1080     (define-key map "H"         #'display-local-help)
   1081     (define-key map "i"         #'flycheck-manual)
   1082     (define-key map "V"         #'flycheck-version)
   1083     (define-key map "v"         #'flycheck-verify-setup)
   1084     (define-key map "x"         #'flycheck-disable-checker)
   1085     map)
   1086   "Keymap of Flycheck interactive commands.")
   1087 
   1088 (defcustom flycheck-keymap-prefix (kbd "C-c !")
   1089   "Prefix for key bindings of Flycheck.
   1090 
   1091 Changing this variable outside Customize does not have any
   1092 effect.  To change the keymap prefix from Lisp, you need to
   1093 explicitly re-define the prefix key:
   1094 
   1095     (define-key flycheck-mode-map flycheck-keymap-prefix nil)
   1096     (setq flycheck-keymap-prefix (kbd \"C-c f\"))
   1097     (define-key flycheck-mode-map flycheck-keymap-prefix
   1098                 flycheck-command-map)
   1099 
   1100 Please note that Flycheck's manual documents the default
   1101 keybindings.  Changing this variable is at your own risk."
   1102   :group 'flycheck
   1103   :package-version '(flycheck . "0.19")
   1104   :type 'string
   1105   :risky t
   1106   :set
   1107   (lambda (variable key)
   1108     (when (and (boundp variable) (boundp 'flycheck-mode-map))
   1109       (define-key flycheck-mode-map (symbol-value variable) nil)
   1110       (define-key flycheck-mode-map key flycheck-command-map))
   1111     (set-default variable key)))
   1112 
   1113 (defcustom flycheck-mode-line '(:eval (flycheck-mode-line-status-text))
   1114   "Mode line lighter for Flycheck.
   1115 
   1116 The value of this variable is a mode line template as in
   1117 `mode-line-format'.  See Info Node `(elisp)Mode Line Format' for
   1118 more information.  Note that it should contain a _single_ mode
   1119 line construct only.
   1120 
   1121 Customize this variable to change how Flycheck reports its status
   1122 in the mode line.  You may use `flycheck-mode-line-status-text'
   1123 to obtain a human-readable status text, including an
   1124 error/warning count.
   1125 
   1126 You may also assemble your own status text.  The current status
   1127 of Flycheck is available in `flycheck-last-status-change'.  The
   1128 errors in the current buffer are stored in
   1129 `flycheck-current-errors', and the function
   1130 `flycheck-count-errors' may be used to obtain the number of
   1131 errors grouped by error level.
   1132 
   1133 Set this variable to nil to disable the mode line completely."
   1134   :group 'flycheck
   1135   :type 'sexp
   1136   :risky t
   1137   :package-version '(flycheck . "0.20"))
   1138 
   1139 (defcustom flycheck-mode-line-color t
   1140   "Use colors for Flycheck mode line status."
   1141   :group 'flycheck
   1142   :type 'boolean
   1143   :package-version '(flycheck . "35"))
   1144 
   1145 (defcustom flycheck-mode-line-prefix "FlyC"
   1146   "Base mode line lighter for Flycheck.
   1147 
   1148 This will have an effect only with the default
   1149 `flycheck-mode-line'.
   1150 
   1151 If you've customized `flycheck-mode-line' then the customized
   1152 function must be updated to use this variable."
   1153   :group 'flycheck
   1154   :type 'string
   1155   :package-version '(flycheck . "26"))
   1156 
   1157 (defcustom flycheck-mode-success-indicator ":0"
   1158   "Success indicator appended to `flycheck-mode-line-prefix'."
   1159   :group 'flycheck
   1160   :type 'string
   1161   :package-version '(flycheck . "35"))
   1162 
   1163 (defcustom flycheck-error-list-mode-line
   1164   `(,(propertized-buffer-identification "%12b")
   1165     " for buffer "
   1166     (:eval (flycheck-error-list-propertized-source-name))
   1167     (:eval (flycheck-error-list-mode-line-filter-indicator)))
   1168   "Mode line construct for Flycheck error list.
   1169 
   1170 The value of this variable is a mode line template as in
   1171 `mode-line-format', to be used as
   1172 `mode-line-buffer-identification' in `flycheck-error-list-mode'.
   1173 See Info Node `(elisp)Mode Line Format' for more information.
   1174 
   1175 Customize this variable to change how the error list appears in
   1176 the mode line.  The default shows the name of the buffer and the
   1177 name of the source buffer, i.e. the buffer whose errors are
   1178 currently listed."
   1179   :group 'flycheck
   1180   :type 'sexp
   1181   :risky t
   1182   :package-version '(flycheck . "0.20"))
   1183 
   1184 (defcustom flycheck-global-modes t
   1185   "Modes for which option `flycheck-mode' is turned on.
   1186 
   1187 If t, Flycheck Mode is turned on for all major modes.  If a list,
   1188 Flycheck Mode is turned on for all `major-mode' symbols in that
   1189 list.  If the `car' of the list is `not', Flycheck Mode is turned
   1190 on for all `major-mode' symbols _not_ in that list.  If nil,
   1191 Flycheck Mode is never turned on by command
   1192 `global-flycheck-mode'.
   1193 
   1194 Note that Flycheck is never turned on for modes whose
   1195 `mode-class' property is `special' (see Info node `(elisp)Major
   1196 Mode Conventions'), regardless of the value of this option.
   1197 
   1198 Only has effect when variable `global-flycheck-mode' is non-nil."
   1199   :group 'flycheck
   1200   :type '(choice (const :tag "none" nil)
   1201                  (const :tag "all" t)
   1202                  (set :menu-tag "mode specific" :tag "modes"
   1203                       :value (not)
   1204                       (const :tag "Except" not)
   1205                       (repeat :inline t (symbol :tag "mode"))))
   1206   :risky t
   1207   :package-version '(flycheck . "0.23"))
   1208 
   1209 ;; Add built-in functions to our hooks, via `add-hook', to make sure that our
   1210 ;; functions are really present, even if the variable was implicitly defined by
   1211 ;; another call to `add-hook' that occurred before Flycheck was loaded.  See
   1212 ;; https://lists.gnu.org/archive/html/emacs-devel/2015-02/msg01271.html for why
   1213 ;; we don't initialize the hook variables right away.  We append our own
   1214 ;; functions, because a user likely expects that their functions come first,
   1215 ;; even if they added them before Flycheck was loaded.
   1216 (dolist (hook (list #'flycheck-locate-config-file-by-path
   1217                     #'flycheck-locate-config-file-ancestor-directories
   1218                     #'flycheck-locate-config-file-home))
   1219   (add-hook 'flycheck-locate-config-file-functions hook 'append))
   1220 
   1221 (add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append)
   1222 
   1223 
   1224 ;;; Global Flycheck menu
   1225 (defvar flycheck-mode-menu-map
   1226   (easy-menu-create-menu
   1227    "Syntax Checking"
   1228    '(["Enable on-the-fly syntax checking" flycheck-mode
   1229       :style toggle :selected flycheck-mode
   1230       :enable (or flycheck-mode
   1231                   ;; Don't let users toggle the mode if there is no syntax
   1232                   ;; checker for this buffer
   1233                   (seq-find #'flycheck-checker-supports-major-mode-p
   1234                             flycheck-checkers))]
   1235      ["Check current buffer" flycheck-buffer flycheck-mode]
   1236      ["Clear errors in buffer" flycheck-clear t]
   1237      ["Run checker as compile command" flycheck-compile flycheck-mode]
   1238      "---"
   1239      ["Go to next error" flycheck-next-error flycheck-mode]
   1240      ["Go to previous error" flycheck-previous-error flycheck-mode]
   1241      ["Show all errors" flycheck-list-errors flycheck-mode]
   1242      "---"
   1243      ["Copy messages at point" flycheck-copy-errors-as-kill
   1244       (flycheck-overlays-at (point))]
   1245      ["Explain error at point" flycheck-explain-error-at-point]
   1246      "---"
   1247      ["Select syntax checker" flycheck-select-checker flycheck-mode]
   1248      ["Disable syntax checker" flycheck-disable-checker flycheck-mode]
   1249      ["Set executable of syntax checker" flycheck-set-checker-executable
   1250       flycheck-mode]
   1251      "---"
   1252      ["Describe syntax checker" flycheck-describe-checker t]
   1253      ["Verify setup" flycheck-verify-setup t]
   1254      ["Show Flycheck version" flycheck-version t]
   1255      ["Flycheck quick help" flycheck-quick-help t]
   1256      ["Read the Flycheck manual" flycheck-manual t]))
   1257   "Menu of command `flycheck-mode'.")
   1258 
   1259 (easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking")
   1260 
   1261 
   1262 
   1263 (defconst flycheck-version "35.0-snapshot"
   1264   "The current version of Flycheck.
   1265 
   1266 Should be kept in sync with the package version metadata.
   1267 Used only when `package-get-function' is not available
   1268 or fails.")
   1269 
   1270 (defun flycheck--pkg-version ()
   1271   "Extract FLYCHECK's package version from its package metadata."
   1272   ;; Use `cond' below to avoid a compiler unused return value warning
   1273   ;; when `package-get-version' returns nil. See #3181.
   1274   (cond ((fboundp 'package-get-version)
   1275          (package-get-version))
   1276         ((fboundp 'pkg-info-version-info)
   1277          (pkg-info-version-info 'flycheck))
   1278         (t
   1279          flycheck-version)))
   1280 
   1281 ;;; Version information, manual and loading of Flycheck
   1282 (defun flycheck-version (&optional show-version)
   1283   "Get the Flycheck version as string.
   1284 
   1285 If called interactively or if SHOW-VERSION is non-nil, show the
   1286 version in the echo area and the messages buffer.
   1287 
   1288 The returned string includes both, the version from package.el
   1289 and the library version, if both a present and different.
   1290 
   1291 If the version number could not be determined, signal an error,
   1292 if called interactively, or if SHOW-VERSION is non-nil, otherwise
   1293 just return nil."
   1294   (interactive (list t))
   1295   (let ((version (flycheck--pkg-version)))
   1296     (when show-version
   1297       (message "Flycheck version: %s" version))
   1298     version))
   1299 
   1300 (defun flycheck-unload-function ()
   1301   "Unload function for Flycheck."
   1302   (global-flycheck-mode -1)
   1303   (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map))
   1304   (remove-hook 'kill-emacs-hook #'flycheck-global-teardown)
   1305   (setq find-function-regexp-alist
   1306         (assq-delete-all 'flycheck-checker find-function-regexp-alist)))
   1307 
   1308 ;;;###autoload
   1309 (defun flycheck-manual ()
   1310   "Open the Flycheck manual."
   1311   (interactive)
   1312   (browse-url "https://www.flycheck.org"))
   1313 
   1314 ;;;###autoload
   1315 (defun flycheck-quick-help ()
   1316   "Display brief Flycheck help."
   1317   (interactive)
   1318   (with-current-buffer (get-buffer-create "*flycheck-quick-help*")
   1319     (with-help-window (current-buffer)
   1320       (flycheck-mode) ;; so that we can exapnd \\[flycheck-<function>]
   1321       (let ((help
   1322              (substitute-command-keys
   1323         "Flycheck automatically runs checks on writable files when changed.
   1324 Mode line status for the current buffer:
   1325   FlyC        Not been checked yet
   1326   FlyC*       Flycheck is running
   1327   FlyC:0      Last check resulted in no errors and no warnings
   1328   FlyC:3|5    Checker reported three errors and five warnings
   1329   FlyC-       No checker available
   1330   FlyC!       The checker crashed
   1331   FlyC.       The last syntax check was manually interrupted
   1332   FlyC?       The checker did something unexpected
   1333 
   1334 Key bindings:
   1335   \\[flycheck-buffer]     Check current buffer
   1336   \\[flycheck-clear]     Clear errors in current buffer
   1337   \\[flycheck-compile]   Run checker as compile command
   1338 
   1339   \\[flycheck-next-error]     Next error
   1340   \\[flycheck-previous-error]     Previous error
   1341   \\[flycheck-list-errors]     List all errors
   1342 
   1343   \\[flycheck-copy-errors-as-kill]   Copy error messages at point
   1344   \\[flycheck-display-error-at-point]     Explain error at point
   1345 ")))
   1346         (help-mode)
   1347         (read-only-mode 0)
   1348         (insert help)))))
   1349 
   1350 (define-obsolete-function-alias 'flycheck-info
   1351   'flycheck-manual "Flycheck 26" "Open the Flycheck manual.")
   1352 
   1353 
   1354 ;;; Utility functions
   1355 (defun flycheck-sexp-to-string (sexp)
   1356   "Convert SEXP to a string.
   1357 
   1358 Like `prin1-to-string' but ensure that the returned string
   1359 is loadable."
   1360   (let ((print-quoted t)
   1361         (print-length nil)
   1362         (print-level nil))
   1363     (prin1-to-string sexp)))
   1364 
   1365 (defun flycheck-string-to-number-safe (string)
   1366   "Safely convert STRING to a number.
   1367 
   1368 If STRING is of string type and a numeric string, convert STRING
   1369 to a number and return it.  Otherwise return nil."
   1370   (let ((number-re (rx string-start (one-or-more (any digit)) string-end)))
   1371     (when (and (stringp string) (string-match-p number-re string))
   1372       (string-to-number string))))
   1373 
   1374 (defun flycheck-string-or-nil-p (obj)
   1375   "Determine if OBJ is a string or nil."
   1376   (or (null obj) (stringp obj)))
   1377 
   1378 (defun flycheck-string-list-p (obj)
   1379   "Determine if OBJ is a list of strings."
   1380   (and (listp obj) (seq-every-p #'stringp obj)))
   1381 
   1382 (defun flycheck-string-or-string-list-p (obj)
   1383   "Determine if OBJ is a string or a list of strings."
   1384   (or (stringp obj) (flycheck-string-list-p obj)))
   1385 
   1386 (defun flycheck-symbol-list-p (obj)
   1387   "Determine if OBJ is a list of symbols."
   1388   (and (listp obj) (seq-every-p #'symbolp obj)))
   1389 
   1390 (defvar-local flycheck--file-truename-cache nil)
   1391 
   1392 (defun flycheck--file-truename (file)
   1393   "Memoize the result of `file-truename' on (directory-file-name FILE)."
   1394   ;; `file-truename' is slow, but alternatives are incomplete, so memoizing is
   1395   ;; our best bet.  See https://github.com/flycheck/flycheck/pull/1698.
   1396   (unless flycheck--file-truename-cache
   1397     (setq-local flycheck--file-truename-cache (make-hash-table :test 'equal)))
   1398   (or (gethash file flycheck--file-truename-cache)
   1399       (puthash file (file-truename (directory-file-name file))
   1400                flycheck--file-truename-cache)))
   1401 
   1402 (defun flycheck-same-files-p (file-a file-b)
   1403   "Determine whether FILE-A and FILE-B refer to the same file.
   1404 
   1405 Files are the same if (in the order checked) they are equal, or
   1406 if they resolve to the same canonical paths."
   1407   (or (string= file-a file-b)
   1408       (string= (flycheck--file-truename file-a)
   1409                (flycheck--file-truename file-b))))
   1410 
   1411 (defvar-local flycheck-temporaries nil
   1412   "Temporary files and directories created by Flycheck.")
   1413 
   1414 (defun flycheck-temp-dir-system ()
   1415   "Create a unique temporary directory.
   1416 
   1417 Use `flycheck-temp-prefix' as prefix, and add the directory to
   1418 `flycheck-temporaries'.
   1419 
   1420 Return the path of the directory"
   1421   (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory)))
   1422     (push tempdir flycheck-temporaries)
   1423     tempdir))
   1424 
   1425 (defun flycheck-temp-file-system (filename &optional suffix)
   1426   "Create a temporary file named after FILENAME.
   1427 
   1428 If FILENAME is non-nil, this function creates a temporary
   1429 directory with `flycheck-temp-dir-system', and creates a file
   1430 with the same name as FILENAME in this directory.
   1431 
   1432 Otherwise this function creates a temporary file starting with
   1433 `flycheck-temp-prefix'.  If present, SUFFIX is appended;
   1434 otherwise, a random suffix is used.  The path of the file is
   1435 added to `flycheck-temporaries'.
   1436 
   1437 Return the path of the file."
   1438   (let ((tempfile (convert-standard-filename
   1439                    (if filename
   1440                        (expand-file-name (file-name-nondirectory filename)
   1441                                          (flycheck-temp-dir-system))
   1442                      (make-temp-file flycheck-temp-prefix nil suffix)))))
   1443     (push tempfile flycheck-temporaries)
   1444     tempfile))
   1445 
   1446 (defun flycheck-temp-file-inplace (filename &optional suffix)
   1447   "Create an in-place copy of FILENAME.
   1448 
   1449 Prefix the file with `flycheck-temp-prefix' and add the path of
   1450 the file to `flycheck-temporaries'.
   1451 
   1452 If FILENAME is nil, fall back to `flycheck-temp-file-system' with
   1453 the specified SUFFIX.
   1454 
   1455 Return the path of the file."
   1456   (if filename
   1457       (let* ((tempname (format "%s_%s"
   1458                                flycheck-temp-prefix
   1459                                (file-name-nondirectory filename)))
   1460              (tempfile (convert-standard-filename
   1461                         (expand-file-name tempname
   1462                                           (file-name-directory filename)))))
   1463         (push tempfile flycheck-temporaries)
   1464         tempfile)
   1465     (flycheck-temp-file-system filename suffix)))
   1466 
   1467 (defun flycheck-temp-directory (checker)
   1468   "Return the directory where CHECKER writes temporary files.
   1469 
   1470 Return nil if the CHECKER does not write temporary files."
   1471   (let ((args (flycheck-checker-arguments checker)))
   1472     (cond
   1473      ((memq 'source args) temporary-file-directory)
   1474      ((memq 'source-inplace args)
   1475       (if buffer-file-name (file-name-directory buffer-file-name)
   1476         temporary-file-directory))
   1477      (t nil))))
   1478 
   1479 (defun flycheck-temp-files-writable-p (checker)
   1480   "Whether CHECKER can write temporary files.
   1481 
   1482 If CHECKER has `source' or `source-inplace' in its `:command',
   1483 return whether flycheck has the permissions to create the
   1484 respective temporary files.
   1485 
   1486 Return t if CHECKER does not use temporary files."
   1487   (let ((dir (flycheck-temp-directory checker)))
   1488     (or (not dir) (file-writable-p dir))))
   1489 
   1490 (defun flycheck-save-buffer-to-file (file-name)
   1491   "Save the contents of the current buffer to FILE-NAME."
   1492   (make-directory (file-name-directory file-name) t)
   1493   (let ((jka-compr-inhibit t))
   1494     (write-region nil nil file-name nil 0)))
   1495 
   1496 (defun flycheck-save-buffer-to-temp (temp-file-fn)
   1497   "Save buffer to temp file returned by TEMP-FILE-FN.
   1498 
   1499 Return the name of the temporary file."
   1500   (let ((filename (funcall temp-file-fn (buffer-file-name))))
   1501     ;; Do not flush short-lived temporary files onto disk
   1502     (let ((write-region-inhibit-fsync t))
   1503       (flycheck-save-buffer-to-file filename))
   1504     filename))
   1505 
   1506 (defun flycheck-prepend-with-option (option items &optional prepend-fn)
   1507   "Prepend OPTION to each item in ITEMS, using PREPEND-FN.
   1508 
   1509 Prepend OPTION to each item in ITEMS.
   1510 
   1511 ITEMS is a list of strings to pass to the syntax checker.  OPTION
   1512 is the option, as string.  PREPEND-FN is a function called to
   1513 prepend OPTION to each item in ITEMS.  It receives the option and
   1514 a single item from ITEMS as argument, and must return a string or
   1515 a list of strings with OPTION prepended to the item.  If
   1516 PREPEND-FN is nil or omitted, use `list'.
   1517 
   1518 Return a list of strings where OPTION is prepended to each item
   1519 in ITEMS using PREPEND-FN.  If PREPEND-FN returns a list, it is
   1520 spliced into the resulting list."
   1521   (unless (stringp option)
   1522     (error "Option %S is not a string" option))
   1523   (unless prepend-fn
   1524     (setq prepend-fn #'list))
   1525   (let ((prepend
   1526          (lambda (item)
   1527            (let ((result (funcall prepend-fn option item)))
   1528              (cond
   1529               ((and (listp result) (seq-every-p #'stringp result)) result)
   1530               ((stringp result) (list result))
   1531               (t (error "Invalid result type for option: %S" result)))))))
   1532     (apply #'append (seq-map prepend items))))
   1533 
   1534 (defun flycheck-find-in-buffer (pattern)
   1535   "Find PATTERN in the current buffer.
   1536 
   1537 Return the result of the first matching group of PATTERN, or nil,
   1538 if PATTERN did not match."
   1539   (save-excursion
   1540     (save-restriction
   1541       (widen)
   1542       (goto-char (point-min))
   1543       (when (re-search-forward pattern nil 'no-error)
   1544         (match-string-no-properties 1)))))
   1545 
   1546 (defun flycheck-buffer-empty-p (&optional buffer)
   1547   "Check whether a BUFFER is empty, defaulting to the current one."
   1548   (= (buffer-size buffer) 0))
   1549 
   1550 (defun flycheck-buffer-nonempty-p (&optional buffer)
   1551   "Check whether a BUFFER is nonempty, defaulting to the current one."
   1552   (> (buffer-size buffer) 0))
   1553 
   1554 (defun flycheck-ephemeral-buffer-p ()
   1555   "Determine whether the current buffer is an ephemeral buffer.
   1556 
   1557 See Info node `(elisp)Buffer Names' for information about
   1558 ephemeral buffers."
   1559   (string-prefix-p " " (buffer-name)))
   1560 
   1561 (defun flycheck-encrypted-buffer-p ()
   1562   "Determine whether the current buffer is an encrypted file.
   1563 
   1564 See Info node `(epa)Top' for Emacs' interface to encrypted
   1565 files."
   1566   ;; The EPA file handler sets this variable locally to remember the recipients
   1567   ;; of the encrypted file for re-encryption.  Hence, a local binding of this
   1568   ;; variable is a good indication that the buffer is encrypted.  I haven't
   1569   ;; found any better indicator anyway.
   1570   (local-variable-p 'epa-file-encrypt-to))
   1571 
   1572 (defun flycheck-autoloads-file-p ()
   1573   "Determine whether the current buffer is an autoloads file.
   1574 
   1575 Autoloads are generated by package.el during installation."
   1576   (string-suffix-p "-autoloads.el" (buffer-name)))
   1577 
   1578 (defun flycheck-in-user-emacs-directory-p (filename)
   1579   "Whether FILENAME is in `user-emacs-directory'."
   1580   (string-prefix-p (file-name-as-directory
   1581                     (flycheck--file-truename user-emacs-directory))
   1582                    (flycheck--file-truename filename)))
   1583 
   1584 (defun flycheck-safe-delete (file-or-dir)
   1585   "Safely delete FILE-OR-DIR."
   1586   (ignore-errors
   1587     (if (file-directory-p file-or-dir)
   1588         (delete-directory file-or-dir 'recursive)
   1589       (delete-file file-or-dir))))
   1590 
   1591 (defun flycheck-safe-delete-temporaries ()
   1592   "Safely delete all temp files and directories of Flycheck.
   1593 
   1594 Safely delete all files and directories listed in
   1595 `flycheck-temporaries' and set the variable's value to nil."
   1596   (seq-do #'flycheck-safe-delete flycheck-temporaries)
   1597   (setq flycheck-temporaries nil))
   1598 
   1599 (defun flycheck-rx-file-name (form)
   1600   "Translate the `(file-name)' FORM into a regular expression."
   1601   (let ((body (or (cdr form) '((minimal-match
   1602                                 (one-or-more not-newline))))))
   1603     (rx-to-string `(group-n 1 ,@body) t)))
   1604 
   1605 (defun flycheck-rx-message (form)
   1606   "Translate the `(message)' FORM into a regular expression."
   1607   (let ((body (or (cdr form) '((one-or-more not-newline)))))
   1608     (rx-to-string `(group-n 4 ,@body) t)))
   1609 
   1610 (defun flycheck-rx-id (form)
   1611   "Translate the `(id)' FORM into a regular expression."
   1612   (rx-to-string `(group-n 5 ,@(cdr form)) t))
   1613 
   1614 (defun flycheck-rx-to-string (form &optional no-group)
   1615   "Like `rx-to-string' for FORM, but with special keywords:
   1616 
   1617 `line'
   1618      matches the initial line number.
   1619 
   1620 `column'
   1621      matches the initial column number.
   1622 
   1623 `end-line'
   1624      matches the final line number.
   1625 
   1626 `end-column'
   1627      matches the final column number (exclusive).
   1628 
   1629 
   1630 `(file-name SEXP ...)'
   1631      matches the file name.  SEXP describes the file name.  If no
   1632      SEXP is given, use a default body of `(minimal-match
   1633      (one-or-more not-newline))'.
   1634 
   1635 `(message SEXP ...)'
   1636      matches the message.  SEXP constitutes the body of the
   1637      message.  If no SEXP is given, use a default body
   1638      of `(one-or-more not-newline)'.
   1639 
   1640 `(id SEXP ...)'
   1641      matches an error ID.  SEXP describes the ID.
   1642 
   1643 NO-GROUP is passed to `rx-to-string'.
   1644 
   1645 See `rx' for a complete list of all built-in `rx' forms."
   1646   (let ((rx-constituents
   1647          (append
   1648           `((file-name flycheck-rx-file-name 0 nil) ;; group 1
   1649             (line . ,(rx (group-n 2 (one-or-more digit))))
   1650             (column . ,(rx (group-n 3 (one-or-more digit))))
   1651             (message flycheck-rx-message 0 nil) ;; group 4
   1652             (id flycheck-rx-id 0 nil) ;; group 5
   1653             (end-line . ,(rx (group-n 6 (one-or-more digit))))
   1654             (end-column . ,(rx (group-n 7 (one-or-more digit)))))
   1655           rx-constituents nil)))
   1656     (rx-to-string form no-group)))
   1657 
   1658 (defun flycheck-current-load-file ()
   1659   "Get the source file currently being loaded.
   1660 
   1661 Always return the name of the corresponding source file, never
   1662 any byte-compiled file.
   1663 
   1664 Return nil, if the currently loaded file cannot be determined."
   1665   (when-let* ((this-file (cond
   1666                           (load-in-progress load-file-name)
   1667                           ((bound-and-true-p byte-compile-current-file))
   1668                           (t (buffer-file-name))))
   1669               ;; A best guess for the source file of a compiled library. Works
   1670               ;; well in most cases, and especially for ELPA packages
   1671               (source-file (concat (file-name-sans-extension this-file)
   1672                                    ".el")))
   1673     (when (file-exists-p source-file)
   1674       source-file)))
   1675 
   1676 (defun flycheck-module-root-directory (module &optional file-name)
   1677   "Get the root directory for a MODULE in FILE-NAME.
   1678 
   1679 MODULE is a qualified module name, either a string with
   1680 components separated by a dot, or as list of components.
   1681 FILE-NAME is the name of the file or directory containing the
   1682 module as string.  When nil or omitted, defaults to the return
   1683 value of function `buffer-file-name'.
   1684 
   1685 Return the root directory of the module, that is, the directory,
   1686 from which FILE-NAME can be reached by descending directories
   1687 along each part of MODULE.
   1688 
   1689 If the MODULE name does not match the directory hierarchy upwards
   1690 from FILE-NAME, return the directory containing FILE-NAME.  When
   1691 FILE-NAME is nil, return `default-directory'."
   1692   (let ((file-name (or file-name (buffer-file-name)))
   1693         (module-components (if (stringp module)
   1694                                (split-string module (rx "."))
   1695                              (copy-sequence module))))
   1696     (if (and module-components file-name)
   1697         (let ((parts (nreverse module-components))
   1698               (base-directory (directory-file-name
   1699                                (file-name-sans-extension file-name))))
   1700           (while (and parts
   1701                       (string= (file-name-nondirectory base-directory)
   1702                                (car parts)))
   1703             (pop parts)
   1704             (setq base-directory (directory-file-name
   1705                                   (file-name-directory base-directory))))
   1706           (file-name-as-directory base-directory))
   1707       (if file-name
   1708           (file-name-directory file-name)
   1709         (expand-file-name default-directory)))))
   1710 
   1711 (cl-defstruct (flycheck-line-cache
   1712                (:constructor flycheck-line-cache-new))
   1713   "Cache structure used to speed up `flycheck-goto-line'."
   1714   tick point line)
   1715 
   1716 (defvar-local flycheck--line-cache nil
   1717   "Cache used to speed ip `flycheck-goto-line'.")
   1718 
   1719 (defsubst flycheck--init-line-cache ()
   1720   "Initialize or reinitialize `flycheck--line-cache'."
   1721   (let ((tick (buffer-modified-tick)))
   1722     (if flycheck--line-cache
   1723         (unless (= (flycheck-line-cache-tick flycheck--line-cache) tick)
   1724           (setf (flycheck-line-cache-tick flycheck--line-cache) tick
   1725                 (flycheck-line-cache-point flycheck--line-cache) 1
   1726                 (flycheck-line-cache-line flycheck--line-cache) 1))
   1727       (setq-local flycheck--line-cache
   1728                   (flycheck-line-cache-new :tick tick :point 1 :line 1)))))
   1729 
   1730 (defun flycheck-goto-line (line)
   1731   "Move point to beginning of line number LINE.
   1732 
   1733 This function assumes that the current buffer is not narrowed."
   1734   (flycheck--init-line-cache)
   1735   (goto-char (flycheck-line-cache-point flycheck--line-cache))
   1736   (let ((delta (- line (flycheck-line-cache-line flycheck--line-cache))))
   1737     (when (= 0 (forward-line delta))
   1738       (setf (flycheck-line-cache-point flycheck--line-cache) (point))
   1739       (setf (flycheck-line-cache-line flycheck--line-cache) line))))
   1740 
   1741 (defun flycheck-line-column-to-position (line column)
   1742   "Return the point closest to LINE, COLUMN on line LINE.
   1743 
   1744 COLUMN is one-based."
   1745   (save-excursion
   1746     (flycheck-goto-line line)
   1747     (min (+ (point) (1- column)) (line-end-position))))
   1748 
   1749 (defun flycheck-line-column-at-point ()
   1750   "Return the line and column number at point."
   1751   (cons (line-number-at-pos) (1+ (- (point) (line-beginning-position)))))
   1752 
   1753 (defun flycheck-line-column-at-pos (pos)
   1754   "Return the line and column number at position POS.
   1755 
   1756 COLUMN is one-based."
   1757   (let ((inhibit-field-text-motion t))
   1758     (save-excursion
   1759       (goto-char pos)
   1760       (flycheck-line-column-at-point))))
   1761 
   1762 
   1763 ;;; Minibuffer tools
   1764 (defvar flycheck-read-checker-history nil
   1765   "`completing-read' history of `flycheck-read-checker'.")
   1766 
   1767 (defun flycheck-completing-read (prompt candidates default &optional history)
   1768   "Read a value from the minibuffer.
   1769 
   1770 Use `flycheck-completing-read-function' to read input from the
   1771 minibuffer with completion.
   1772 
   1773 Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT.
   1774 HISTORY is passed to `flycheck-completing-read-function'.
   1775 
   1776 Note that `flycheck-completing-read-function' may return an empty
   1777 string instead of nil, even when \"\" isn't among the candidates.
   1778 See `completing-read' for more details."
   1779   (funcall flycheck-completing-read-function
   1780            prompt candidates nil 'require-match nil history default))
   1781 
   1782 (defun flycheck-read-checker (prompt &optional default property candidates)
   1783   "Read a flycheck checker from minibuffer with PROMPT and DEFAULT.
   1784 
   1785 PROMPT is a string to show in the minibuffer as prompt.  It
   1786 should end with a single space.  DEFAULT is a symbol denoting the
   1787 default checker to use, if the user did not select any checker.
   1788 PROPERTY is a symbol denoting a syntax checker property.  If
   1789 non-nil, only complete syntax checkers which have a non-nil value
   1790 for PROPERTY.  CANDIDATES is an optional list of all syntax
   1791 checkers available for completion, defaulting to all defined
   1792 checkers.  If given, PROPERTY is ignored.
   1793 
   1794 Return the checker as symbol, or DEFAULT if no checker was
   1795 chosen.  If DEFAULT is nil and no checker was chosen, signal a
   1796 `user-error' if the underlying completion system does not provide
   1797 a default on its own."
   1798   (when (and default (not (flycheck-valid-checker-p default)))
   1799     (error "%S is no valid Flycheck checker" default))
   1800   (let* ((candidates (seq-map #'symbol-name
   1801                               (or candidates
   1802                                   (flycheck-defined-checkers property))))
   1803          (default (and default (symbol-name default)))
   1804          (input (flycheck-completing-read
   1805                  prompt candidates default
   1806                  'flycheck-read-checker-history)))
   1807     (when (string-empty-p input)
   1808       (unless default
   1809         (user-error "No syntax checker selected"))
   1810       (setq input default))
   1811     (let ((checker (intern input)))
   1812       (unless (flycheck-valid-checker-p checker)
   1813         (error "%S is not a valid Flycheck syntax checker" checker))
   1814       checker)))
   1815 
   1816 (defun flycheck-read-error-level (prompt)
   1817   "Read an error level from the user with PROMPT.
   1818 
   1819 Only offers level for which errors currently exist, in addition
   1820 to the default levels."
   1821   (let* ((levels (seq-map #'flycheck-error-level
   1822                           (flycheck-error-list-current-errors)))
   1823          (levels-with-defaults (append '(info warning error) levels))
   1824          (uniq-levels (seq-uniq levels-with-defaults))
   1825          (level (flycheck-completing-read prompt uniq-levels nil)))
   1826     (when (string-empty-p level) (setq level nil))
   1827     (and level (intern level))))
   1828 
   1829 
   1830 ;;; Checker API
   1831 (defun flycheck-defined-checkers (&optional property)
   1832   "Find all defined syntax checkers, optionally with PROPERTY.
   1833 
   1834 PROPERTY is a symbol.  If given, only return syntax checkers with
   1835 a non-nil value for PROPERTY.
   1836 
   1837 The returned list is sorted alphapetically by the symbol name of
   1838 the syntax checkers."
   1839   (let (defined-checkers)
   1840     (mapatoms (lambda (symbol)
   1841                 (when (and (flycheck-valid-checker-p symbol)
   1842                            (or (null property)
   1843                                (flycheck-checker-get symbol property)))
   1844                   (push symbol defined-checkers))))
   1845     (sort defined-checkers #'string<)))
   1846 
   1847 (defun flycheck-registered-checker-p (checker)
   1848   "Determine whether CHECKER is registered.
   1849 
   1850 A checker is registered if it is contained in
   1851 `flycheck-checkers'."
   1852   (and (flycheck-valid-checker-p checker)
   1853        (memq checker flycheck-checkers)))
   1854 
   1855 (defun flycheck-disabled-checker-p (checker)
   1856   "Determine whether CHECKER is disabled, manually or automatically."
   1857   (or (flycheck-manually-disabled-checker-p checker)
   1858       (flycheck-automatically-disabled-checker-p checker)))
   1859 
   1860 (defun flycheck-manually-disabled-checker-p (checker)
   1861   "Determine whether CHECKER has been manually disabled.
   1862 
   1863 A checker has been manually disabled if it is contained in
   1864 `flycheck-disabled-checkers'."
   1865   (memq checker flycheck-disabled-checkers))
   1866 
   1867 (defun flycheck-automatically-disabled-checker-p (checker)
   1868   "Determine whether CHECKER has been automatically disabled.
   1869 
   1870 A checker has been automatically disabled if it is contained in
   1871 `flycheck--automatically-disabled-checkers'."
   1872   (memq checker flycheck--automatically-disabled-checkers))
   1873 
   1874 
   1875 ;;; Generic syntax checkers
   1876 (defconst flycheck-generic-checker-version 2
   1877   "The internal version of generic syntax checker declarations.
   1878 
   1879 Flycheck will not use syntax checkers whose generic version is
   1880 less than this constant.")
   1881 
   1882 (defsubst flycheck--checker-property-name (property)
   1883   "Return the SYMBOL property for checker PROPERTY."
   1884   (intern (concat "flycheck-" (symbol-name property))))
   1885 
   1886 (defun flycheck-checker-get (checker property)
   1887   "Get the value of CHECKER's PROPERTY."
   1888   (get checker (flycheck--checker-property-name property)))
   1889 
   1890 (gv-define-setter flycheck-checker-get (value checker property)
   1891   `(setf (get ,checker (flycheck--checker-property-name ,property)) ,value))
   1892 
   1893 (defun flycheck-validate-next-checker (next &optional strict)
   1894   "Validate NEXT checker.
   1895 
   1896 With STRICT non-nil, also check whether the syntax checker and
   1897 the error level in NEXT are valid.  Otherwise just check whether
   1898 these are symbols.
   1899 
   1900 Signal an error if NEXT is not a valid entry for
   1901 `:next-checkers'."
   1902   (when (symbolp next)
   1903     (setq next (cons t next)))
   1904   (pcase next
   1905     (`(,level . ,checker)
   1906      (if strict
   1907          (progn
   1908            (unless (or (eq level t) (flycheck-error-level-p level))
   1909              (error "%S is not a valid Flycheck error level" level))
   1910            (unless (flycheck-valid-checker-p checker)
   1911              (error "%s is not a valid Flycheck syntax checker" checker)))
   1912        (unless (symbolp level)
   1913          (error "Error level %S must be a symbol" level))
   1914        (unless (symbolp checker)
   1915          (error "Checker %S must be a symbol" checker))))
   1916     (_ (error "%S must be a symbol or cons cell" next)))
   1917   t)
   1918 
   1919 (defun flycheck-define-generic-checker (symbol docstring &rest properties)
   1920   "Define SYMBOL as generic syntax checker.
   1921 
   1922 Any syntax checker defined with this macro is eligible for manual
   1923 syntax checker selection with `flycheck-select-checker'.  To make
   1924 the new syntax checker available for automatic selection, it must
   1925 be registered in `flycheck-checkers'.
   1926 
   1927 DOCSTRING is the documentation of the syntax checker, for
   1928 `flycheck-describe-checker'.  The following PROPERTIES constitute
   1929 a generic syntax checker.  Unless otherwise noted, all properties
   1930 are mandatory.
   1931 
   1932 `:start FUNCTION'
   1933      A function to start the syntax checker.
   1934 
   1935      FUNCTION shall take two arguments and return a context
   1936      object if the checker is started successfully.  Otherwise it
   1937      shall signal an error.
   1938 
   1939      The first argument is the syntax checker being started.  The
   1940      second is a callback function to report state changes to
   1941      Flycheck.  The callback takes two arguments STATUS DATA,
   1942      where STATUS is a symbol denoting the syntax checker status
   1943      and DATA an optional argument with additional data for the
   1944      status report.  See `flycheck-report-buffer-checker-status'
   1945      for more information about STATUS and DATA.
   1946 
   1947      FUNCTION may be synchronous or asynchronous, i.e. it may
   1948      call the given callback either immediately, or at some later
   1949      point (e.g. from a process sentinel).
   1950 
   1951      A syntax checker _must_ call CALLBACK at least once with a
   1952      STATUS that finishes the current syntax checker.  Otherwise
   1953      Flycheck gets stuck at the current syntax check with this
   1954      syntax checker.
   1955 
   1956      The context object returned by FUNCTION is passed to
   1957      `:interrupt'.
   1958 
   1959 `:interrupt FUNCTION'
   1960      A function to interrupt the syntax check.
   1961 
   1962      FUNCTION is called with the syntax checker and the context
   1963      object returned by the `:start' function and shall try to
   1964      interrupt the syntax check.  The context may be nil, if the
   1965      syntax check is interrupted before actually started.
   1966      FUNCTION should handle this situation.
   1967 
   1968      If it cannot interrupt the syntax check, it may either
   1969      signal an error or silently ignore the attempt to interrupt
   1970      the syntax checker, depending on the severity of the
   1971      situation.
   1972 
   1973      If interrupting the syntax check failed, Flycheck will let
   1974      the syntax check continue, but ignore any status reports.
   1975      Notably, it won't highlight any errors reported by the
   1976      syntax check in the buffer.
   1977 
   1978      This property is optional.  If omitted, Flycheck won't
   1979      attempt to interrupt syntax checks with this syntax checker,
   1980      and simply ignore their results.
   1981 
   1982 `:print-doc FUNCTION'
   1983      A function to print additional documentation into the Help
   1984      buffer of this checker.
   1985 
   1986      FUNCTION is called when creating the Help buffer for the
   1987      syntax checker, with the syntax checker as single argument,
   1988      after printing the name of the syntax checker and its modes
   1989      and predicate, but before printing DOCSTRING.  It may insert
   1990      additional documentation into the current buffer.
   1991 
   1992      The call occurs within `with-help-window'.  Hence
   1993      `standard-output' points to the current buffer, so you may
   1994      use `princ' and friends to add content.  Also, the current
   1995      buffer is put into Help mode afterwards, which automatically
   1996      turns symbols into references, if possible.
   1997 
   1998      This property is optional.  If omitted, no additional
   1999      documentation is printed for this syntax checker.
   2000 
   2001 :verify FUNCTION
   2002      A function to verify the checker for the current buffer.
   2003 
   2004      FUNCTION is called with the syntax checker as single
   2005      argument, and shall return a list of
   2006      `flycheck-verification-result' objects indicating whether
   2007      the syntax checker could be used in the current buffer, and
   2008      highlighting potential setup problems.
   2009 
   2010      This property is optional.  If omitted, no additional
   2011      verification occurs for this syntax checker.  It is however
   2012      absolutely recommended that you add a `:verify' function to
   2013      your syntax checker, because it will help users to spot
   2014      potential setup problems.
   2015 
   2016 `:modes MODES'
   2017      A major mode symbol or a list thereof, denoting major modes
   2018      to use this syntax checker in.
   2019 
   2020      This syntax checker will only be used in buffers whose
   2021      `major-mode' is contained in MODES.
   2022 
   2023      If `:predicate' is also given the syntax checker will only
   2024      be used in buffers for which the `:predicate' returns
   2025      non-nil.
   2026 
   2027 `:predicate FUNCTION'
   2028      A function to determine whether to use the syntax checker in
   2029      the current buffer.
   2030 
   2031      FUNCTION is called without arguments and shall return
   2032      non-nil if this syntax checker shall be used to check the
   2033      current buffer.  Otherwise it shall return nil.
   2034 
   2035      If this checker has a `:working-directory' FUNCTION is
   2036      called with `default-directory' bound to the checker's
   2037      working directory.
   2038 
   2039      FUNCTION is only called in matching major modes.
   2040 
   2041      This property is optional.
   2042 
   2043 `:enabled FUNCTION'
   2044      A function to determine whether to use the syntax checker in
   2045      the current buffer.
   2046 
   2047      This property behaves as `:predicate', except that it's only
   2048      called the first time a syntax checker is to be used in a buffer.
   2049 
   2050      FUNCTION is called without arguments and shall return
   2051      non-nil if this syntax checker shall be used to check the
   2052      current buffer.  Otherwise it shall return nil.
   2053 
   2054      If FUNCTION returns a non-nil value the checker is put in a
   2055      whitelist in `flycheck--automatically-enabled-checkers' to
   2056      prevent further invocations of `:enabled'.  Otherwise it is
   2057      disabled via `flycheck--automatically-disabled-checkers' to
   2058      prevent any further use of it.
   2059 
   2060      If this checker has a `:working-directory' FUNCTION is
   2061      called with `default-directory' bound to the checker's
   2062      working directory.
   2063 
   2064      FUNCTION is only called in matching major modes.
   2065 
   2066      This property is optional.
   2067 
   2068 `:error-filter FUNCTION'
   2069      A function to filter the errors returned by this checker.
   2070 
   2071      FUNCTION is called with the list of `flycheck-error' objects
   2072      returned by the syntax checker and shall return another list
   2073      of `flycheck-error' objects, which is considered the final
   2074      result of this syntax checker.
   2075 
   2076      FUNCTION is free to add, remove or modify errors, whether in
   2077      place or by copying.
   2078 
   2079      This property is optional.  The default filter is
   2080      `identity'.
   2081 
   2082 `:error-explainer FUNCTION'
   2083      A function to return an explanation text for errors
   2084      generated by this checker.
   2085 
   2086      FUNCTION is called with a `flycheck-error' object, in the
   2087      buffer of that error.  It shall return an explanation
   2088      message for the error.
   2089 
   2090      The message can take any of the following forms:
   2091      - A string, which will be displayed to the user
   2092      - A function (likely a closure), which will be called with
   2093        `standard-output' set to a `flycheck-explain-error-mode'
   2094        buffer, and should write to it.
   2095      - A cons `(url . ,URL), indicating that the explanation can
   2096        be found online at URL.
   2097      - nil if there is no explanation for this error.
   2098 
   2099      If URL is provided by the checker, and cannot be composed
   2100      from other elements in the `flycheck-error' object, consider
   2101      passing the URL via text properties:
   2102 
   2103        ;; During the error object creation
   2104        (put-text-property 0 1 \\='explainer-url .url .check_id)
   2105 
   2106        ;; In the error-explainer FUNCTION
   2107        (let ((id (flycheck-error-id err)))
   2108          (and id `(url . ,(get-text-property 0 \\='explainer-url id))))
   2109 
   2110      This property is optional.
   2111 
   2112 `:next-checkers NEXT-CHECKERS'
   2113      A list denoting syntax checkers to apply after this syntax
   2114      checker, in what we call \"chaining\" of syntax checkers.
   2115 
   2116      Each ITEM is a cons cell `(LEVEL . CHECKER)'.  CHECKER is a
   2117      syntax checker to run after this syntax checker.  LEVEL is
   2118      an error level.  CHECKER will only be used if there are no
   2119      current errors of at least LEVEL.  LEVEL may also be t, in
   2120      which case CHECKER is used regardless of the current errors.
   2121 
   2122      ITEM may also be a syntax checker symbol, which is
   2123      equivalent to `(t . ITEM)'.
   2124 
   2125      Flycheck tries all items in order of declaration, and uses
   2126      the first whose LEVEL matches and whose CHECKER is
   2127      registered and can be used for the current buffer.
   2128 
   2129      This feature is typically used to apply more than one syntax
   2130      checker to a buffer.  For instance, you might first use a
   2131      compiler to check a buffer for syntax and type errors, and
   2132      then run a linting tool that checks for insecure code, or
   2133      questionable style.
   2134 
   2135      This property is optional.  If omitted, it defaults to the
   2136      nil, i.e. no other syntax checkers are applied after this
   2137      syntax checker.
   2138 
   2139 `:working-directory FUNCTION'
   2140      The value of `default-directory' when invoking `:start'.
   2141 
   2142      FUNCTION is a function taking the syntax checker as sole
   2143      argument.  It shall return the absolute path to an existing
   2144      directory to use as `default-directory' for `:start' or
   2145      nil to fall back to the `default-directory' of the current
   2146      buffer.
   2147 
   2148      This property is optional.  If omitted, invoke `:start'
   2149      from the `default-directory' of the buffer being checked.
   2150 
   2151 Signal an error, if any property has an invalid value."
   2152   (declare (indent 1)
   2153            (doc-string 2))
   2154   (let ((start (plist-get properties :start))
   2155         (interrupt (plist-get properties :interrupt))
   2156         (print-doc (plist-get properties :print-doc))
   2157         (modes (plist-get properties :modes))
   2158         (predicate (plist-get properties :predicate))
   2159         (verify (plist-get properties :verify))
   2160         (enabled (plist-get properties :enabled))
   2161         (filter (or (plist-get properties :error-filter) #'identity))
   2162         (explainer (plist-get properties :error-explainer))
   2163         (next-checkers (plist-get properties :next-checkers))
   2164         (file (flycheck-current-load-file))
   2165         (working-directory (plist-get properties :working-directory)))
   2166 
   2167     (unless (listp modes)
   2168       (setq modes (list modes)))
   2169 
   2170     (unless (functionp start)
   2171       (error ":start %S of syntax checker %s is not a function" start symbol))
   2172     (unless (or (null interrupt) (functionp interrupt))
   2173       (error ":interrupt %S of syntax checker %s is not a function"
   2174              interrupt symbol))
   2175     (unless (or (null print-doc) (functionp print-doc))
   2176       (error ":print-doc %S of syntax checker %s is not a function"
   2177              print-doc symbol))
   2178     (unless (or (null verify) (functionp verify))
   2179       (error ":verify %S of syntax checker %S is not a function"
   2180              verify symbol))
   2181     (unless (or (null enabled) (functionp enabled))
   2182       (error ":enabled %S of syntax checker %S is not a function"
   2183              enabled symbol))
   2184     (unless modes
   2185       (error "Missing :modes in syntax checker %s" symbol))
   2186     (dolist (mode modes)
   2187       (unless (symbolp mode)
   2188         (error "Invalid :modes %s in syntax checker %s, %s must be a symbol"
   2189                modes symbol mode)))
   2190     (unless (or (null predicate) (functionp predicate))
   2191       (error ":predicate %S of syntax checker %s  is not a function"
   2192              predicate symbol))
   2193     (unless (functionp filter)
   2194       (error ":error-filter %S of syntax checker %s is not a function"
   2195              filter symbol))
   2196     (unless (or (null explainer) (functionp explainer))
   2197       (error ":error-explainer %S of syntax checker %S is not a function"
   2198              explainer symbol))
   2199     (dolist (checker next-checkers)
   2200       (flycheck-validate-next-checker checker))
   2201 
   2202     (let ((real-predicate
   2203            (and predicate
   2204                 (lambda ()
   2205                   ;; Run predicate in the checker's default directory
   2206                   (let ((default-directory
   2207                           (flycheck-compute-working-directory symbol)))
   2208                     (funcall predicate)))))
   2209           (real-enabled
   2210            (lambda ()
   2211              (if (flycheck-valid-checker-p symbol)
   2212                  (or (null enabled)
   2213                      ;; Run enabled in the checker's default directory
   2214                      (let ((default-directory
   2215                              (flycheck-compute-working-directory symbol)))
   2216                        (funcall enabled)))
   2217                (lwarn 'flycheck
   2218                       :warning "%S is no valid Flycheck syntax checker.
   2219 Try to reinstall the package defining this syntax checker." symbol)
   2220                nil))))
   2221       (pcase-dolist (`(,prop . ,value)
   2222                      `((start             . ,start)
   2223                        (interrupt         . ,interrupt)
   2224                        (print-doc         . ,print-doc)
   2225                        (modes             . ,modes)
   2226                        (predicate         . ,real-predicate)
   2227                        (verify            . ,verify)
   2228                        (enabled           . ,real-enabled)
   2229                        (error-filter      . ,filter)
   2230                        (error-explainer   . ,explainer)
   2231                        (next-checkers     . ,next-checkers)
   2232                        (documentation     . ,docstring)
   2233                        (file              . ,file)
   2234                        (working-directory . ,working-directory)))
   2235         (setf (flycheck-checker-get symbol prop) value)))
   2236 
   2237     ;; Track the version, to avoid breakage if the internal format changes
   2238     (setf (flycheck-checker-get symbol 'generic-checker-version)
   2239           flycheck-generic-checker-version)))
   2240 
   2241 (defun flycheck-valid-checker-p (checker)
   2242   "Check whether a CHECKER is valid.
   2243 
   2244 A valid checker is a symbol defined as syntax checker with
   2245 `flycheck-define-checker'."
   2246   (and (symbolp checker)
   2247        (= (or (get checker 'flycheck-generic-checker-version) 0)
   2248           flycheck-generic-checker-version)))
   2249 
   2250 (defun flycheck-checker-supports-major-mode-p (checker &optional mode)
   2251   "Whether CHECKER supports the given major MODE.
   2252 
   2253 CHECKER is a syntax checker symbol and MODE a major mode symbol.
   2254 Look at the `modes' property of CHECKER to determine whether
   2255 CHECKER supports buffers in the given major MODE.
   2256 
   2257 MODE defaults to the value of `major-mode' if omitted or nil.
   2258 
   2259 Return non-nil if CHECKER supports MODE and nil otherwise."
   2260   (let ((mode (or mode major-mode)))
   2261     (memq mode (flycheck-checker-get checker 'modes))))
   2262 
   2263 (define-obsolete-variable-alias 'flycheck-enabled-checkers
   2264   'flycheck--automatically-enabled-checkers "32")
   2265 
   2266 (defvar flycheck--automatically-enabled-checkers nil
   2267   "Syntax checkers included in automatic selection.
   2268 
   2269 A list of Flycheck syntax checkers included in automatic
   2270 selection for the current buffer.")
   2271 (make-variable-buffer-local 'flycheck--automatically-enabled-checkers)
   2272 
   2273 (defun flycheck-may-enable-checker (checker)
   2274   "Whether a generic CHECKER may be enabled for current buffer.
   2275 
   2276 Return non-nil if CHECKER may be used for the current buffer, and
   2277 nil otherwise.  The result of the `:enabled' check, if any, is
   2278 cached."
   2279   (and
   2280    ;; May only enable valid checkers
   2281    (flycheck-valid-checker-p checker)
   2282    ;; Don't run the :enabled check if the checker is already disabled…
   2283    (not (flycheck-disabled-checker-p checker))
   2284    (or
   2285     ;; …or if we've already cached the result
   2286     (memq checker flycheck--automatically-enabled-checkers)
   2287     (let* ((enabled (flycheck-checker-get checker 'enabled))
   2288            (may-enable (or (null enabled) (funcall enabled))))
   2289       ;; Cache the result
   2290       (if may-enable
   2291           (cl-pushnew checker flycheck--automatically-enabled-checkers)
   2292         (cl-pushnew checker flycheck--automatically-disabled-checkers))
   2293       may-enable))))
   2294 
   2295 (defun flycheck-reset-enabled-checker (checker)
   2296   "Reset the `:enabled' test of CHECKER.
   2297 
   2298 Forget that CHECKER has been enabled or automatically disabled
   2299 from a previous `:enabled' test.  The result of the `:enabled'
   2300 test is cached in `flycheck-may-enable-checker': if you wish to
   2301 test the `:enabled' predicate again, you must first reset its
   2302 state using this function."
   2303   (when (memq checker flycheck--automatically-disabled-checkers)
   2304     (setq flycheck--automatically-disabled-checkers
   2305           (remq checker flycheck--automatically-disabled-checkers)))
   2306   (when (memq checker flycheck--automatically-enabled-checkers)
   2307     (setq flycheck--automatically-enabled-checkers
   2308           (remq checker flycheck--automatically-enabled-checkers)))
   2309   (flycheck-buffer))
   2310 
   2311 (defun flycheck-may-use-checker (checker)
   2312   "Whether a generic CHECKER may be used.
   2313 
   2314 Return non-nil if CHECKER may be used for the current buffer, and
   2315 nil otherwise."
   2316   (let ((predicate (flycheck-checker-get checker 'predicate)))
   2317     (and (flycheck-valid-checker-p checker)
   2318          (flycheck-checker-supports-major-mode-p checker)
   2319          (flycheck-may-enable-checker checker)
   2320          (or (null predicate) (funcall predicate)))))
   2321 
   2322 (defun flycheck-may-use-next-checker (next-checker)
   2323   "Determine whether NEXT-CHECKER may be used."
   2324   (when (symbolp next-checker)
   2325     (push t next-checker))
   2326   (let ((level (car next-checker))
   2327         (next-checker (cdr next-checker)))
   2328     (and (or (eq level t)
   2329              (flycheck-has-max-current-errors-p level))
   2330          (flycheck-registered-checker-p next-checker)
   2331          (flycheck-may-use-checker next-checker))))
   2332 
   2333 
   2334 ;;; Help for generic syntax checkers
   2335 (define-button-type 'help-flycheck-checker-def
   2336   :supertype 'help-xref
   2337   'help-function #'flycheck-goto-checker-definition
   2338   'help-echo "mouse-1, RET: find Flycheck checker definition")
   2339 
   2340 (defconst flycheck-find-checker-regexp
   2341   (rx line-start (zero-or-more (syntax whitespace))
   2342       "(" symbol-start
   2343       (or "flycheck-define-checker" "flycheck-define-command-checker")
   2344       symbol-end
   2345       (eval (list 'regexp find-function-space-re))
   2346       (? "'")
   2347       symbol-start "%s" symbol-end
   2348       (or (syntax whitespace) line-end))
   2349   "Regular expression to find a checker definition.")
   2350 
   2351 (add-to-list 'find-function-regexp-alist
   2352              '(flycheck-checker . flycheck-find-checker-regexp))
   2353 
   2354 (defun flycheck-goto-checker-definition (checker file)
   2355   "Go to to the definition of CHECKER in FILE."
   2356   (let ((location (find-function-search-for-symbol
   2357                    checker 'flycheck-checker file)))
   2358     (pop-to-buffer (car location))
   2359     (if (cdr location)
   2360         (goto-char (cdr location))
   2361       (message "Unable to find checker location in file"))))
   2362 
   2363 (defun flycheck-checker-at-point ()
   2364   "Return the Flycheck checker found at or before point.
   2365 
   2366 Return nil if there is no checker."
   2367   (let ((symbol (variable-at-point 'any-symbol)))
   2368     (when (flycheck-valid-checker-p symbol)
   2369       symbol)))
   2370 
   2371 (defun flycheck-describe-checker (checker)
   2372   "Display the documentation of CHECKER.
   2373 
   2374 CHECKER is a checker symbol.
   2375 
   2376 Pop up a help buffer with the documentation of CHECKER."
   2377   (interactive
   2378    (let* ((enable-recursive-minibuffers t)
   2379           (default (or (flycheck-checker-at-point)
   2380                        (ignore-errors (flycheck-get-checker-for-buffer))))
   2381           (prompt (if default
   2382                       (format "Describe syntax checker (default %s): " default)
   2383                     "Describe syntax checker: ")))
   2384      (list (flycheck-read-checker prompt default))))
   2385   (unless (flycheck-valid-checker-p checker)
   2386     (user-error "You didn't specify a Flycheck syntax checker"))
   2387   (let ((filename (flycheck-checker-get checker 'file))
   2388         (modes (flycheck-checker-get checker 'modes))
   2389         (predicate (flycheck-checker-get checker 'predicate))
   2390         (print-doc (flycheck-checker-get checker 'print-doc))
   2391         (next-checkers (flycheck-checker-get checker 'next-checkers))
   2392         (help-xref-following
   2393          ;; Ensure that we don't reuse buffers like `flycheck-verify-checker',
   2394          ;; and that we don't error out if a `help-flycheck-checker-doc' button
   2395          ;; is added outside of a documentation window.
   2396          (and help-xref-following (eq major-mode 'help-mode))))
   2397     (help-setup-xref (list #'flycheck-describe-checker checker)
   2398                      (called-interactively-p 'interactive))
   2399     (save-excursion
   2400       (with-help-window (help-buffer)
   2401         (princ (format "%s is a Flycheck syntax checker" checker))
   2402         (when filename
   2403           (princ (format " in `%s'" (file-name-nondirectory filename)))
   2404           (with-current-buffer standard-output
   2405             (save-excursion
   2406               (re-search-backward "`\\([^`']+\\)'" nil t)
   2407               (help-xref-button 1 'help-flycheck-checker-def
   2408                                 checker filename))))
   2409         (princ ".\n\n")
   2410 
   2411         (let ((modes-start (with-current-buffer standard-output (point-max))))
   2412           ;; Track the start of the modes documentation, to properly re-fill
   2413           ;; it later
   2414           (princ "  This syntax checker checks syntax in the major mode(s) ")
   2415           (princ (string-join
   2416                   (seq-map (apply-partially #'format "`%s'") modes)
   2417                   ", "))
   2418           (when predicate
   2419             (princ ", and uses a custom predicate"))
   2420           (princ ".")
   2421           (when next-checkers
   2422             (princ "  It runs the following checkers afterwards:"))
   2423           (with-current-buffer standard-output
   2424             (save-excursion
   2425               (fill-region-as-paragraph modes-start (point-max))))
   2426           (princ "\n")
   2427 
   2428           ;; Print the list of next checkers
   2429           (when next-checkers
   2430             (princ "\n")
   2431             (let ((beg-checker-list (with-current-buffer standard-output
   2432                                       (point))))
   2433               (dolist (next-checker next-checkers)
   2434                 (if (symbolp next-checker)
   2435                     (princ (format "     * `%s'\n" next-checker))
   2436                   (princ (format "     * `%s' (maximum level `%s')\n"
   2437                                  (cdr next-checker) (car next-checker)))))
   2438               ;;
   2439               (with-current-buffer standard-output
   2440                 (save-excursion
   2441                   (while (re-search-backward "`\\([^`']+\\)'"
   2442                                              beg-checker-list t)
   2443                     (let ((checker (intern-soft (match-string 1))))
   2444                       (when (flycheck-valid-checker-p checker)
   2445                         (help-xref-button 1 'help-flycheck-checker-doc
   2446                                           checker)))))))))
   2447         ;; Call the custom print-doc function of the checker, if present
   2448         (when print-doc
   2449           (funcall print-doc checker))
   2450         ;; Ultimately, print the docstring
   2451         (princ "\nDocumentation:\n")
   2452         (princ (flycheck-checker-get checker 'documentation))))))
   2453 
   2454 
   2455 ;;; Syntax checker verification
   2456 (cl-defstruct (flycheck-verification-result
   2457                (:constructor flycheck-verification-result-new))
   2458   "Structure for storing a single verification result.
   2459 
   2460 Slots:
   2461 
   2462 `label'
   2463      A label for this result, as string
   2464 
   2465 `message'
   2466      A message for this result, as string
   2467 
   2468 `face'
   2469      The face to use for the `message'.
   2470 
   2471      You can either use a face symbol, or a list of face symbols."
   2472   label message face)
   2473 
   2474 (defun flycheck-verify-generic-checker (checker)
   2475   "Verify a generic CHECKER in the current buffer.
   2476 
   2477 Return a list of `flycheck-verification-result' objects."
   2478   (let (results
   2479         (predicate (flycheck-checker-get checker 'predicate))
   2480         (enabled (flycheck-checker-get checker 'enabled))
   2481         (verify (flycheck-checker-get checker 'verify)))
   2482     (when enabled
   2483       (let ((result (funcall enabled)))
   2484         (push (flycheck-verification-result-new
   2485                :label (propertize "may enable" 'help-echo ":enable")
   2486                :message (if result "yes" "no")
   2487                :face (if result 'success '(bold warning)))
   2488               results)))
   2489     (when predicate
   2490       (let ((result (funcall predicate)))
   2491         (push (flycheck-verification-result-new
   2492                :label (propertize "may run" 'help-echo ":predicate")
   2493                :message (prin1-to-string (not (null result)))
   2494                :face (if result 'success '(bold warning)))
   2495               results)))
   2496     (append (nreverse results)
   2497             (and verify (funcall verify checker)))))
   2498 
   2499 (define-button-type 'help-flycheck-checker-doc
   2500   :supertype 'help-xref
   2501   'help-function #'flycheck-describe-checker
   2502   'help-echo "mouse-1, RET: describe Flycheck checker")
   2503 
   2504 (define-button-type 'flycheck-button
   2505   'follow-link t
   2506   'action (lambda (pos)
   2507             (apply (get-text-property pos 'flycheck-action)
   2508                    (get-text-property pos 'flycheck-data))
   2509             ;; Revert the verify-setup buffer since it is now stale
   2510             (revert-buffer))
   2511   'face 'flycheck-verify-select-checker)
   2512 
   2513 (define-button-type 'flycheck-checker-select
   2514   :supertype 'flycheck-button
   2515   'flycheck-action (lambda (buffer checker)
   2516                      (with-current-buffer buffer
   2517                        (flycheck-select-checker checker)))
   2518   'help-echo "mouse-1, RET: select this checker")
   2519 
   2520 (define-button-type 'flycheck-checker-enable
   2521   :supertype 'flycheck-button
   2522   'flycheck-action (lambda (buffer checker)
   2523                      (interactive)
   2524                      (with-current-buffer buffer
   2525                        (flycheck--toggle-checker checker t)
   2526                        (flycheck-buffer)))
   2527   'help-echo "mouse-1, RET: re-enable this checker in this buffer")
   2528 
   2529 (define-button-type 'flycheck-checker-reset-enabled
   2530   :supertype 'flycheck-button
   2531   'flycheck-action (lambda (buffer checker)
   2532                      (with-current-buffer buffer
   2533                        (flycheck-reset-enabled-checker checker)))
   2534   'help-echo "mouse-1, RET: try to re-enable this checker")
   2535 
   2536 (defun flycheck--verify-princ-checker (checker buffer
   2537                                                &optional with-mm with-select)
   2538   "Print verification result of CHECKER for BUFFER.
   2539 
   2540 When WITH-MM is given and non-nil, also include the major mode
   2541 into the verification results.
   2542 
   2543 When WITH-SELECT is non-nil, add a button to select this checker."
   2544   (princ "  ")
   2545   (insert-button (symbol-name checker)
   2546                  'type 'help-flycheck-checker-doc
   2547                  'help-args (list checker))
   2548   (cond
   2549    ((with-current-buffer buffer
   2550       (flycheck-manually-disabled-checker-p checker))
   2551     (insert (propertize " (manually disabled) " 'face '(bold error)))
   2552     (insert-text-button "enable"
   2553                         'type 'flycheck-checker-enable
   2554                         'flycheck-data (list buffer checker)))
   2555    ((with-current-buffer buffer
   2556       (flycheck-automatically-disabled-checker-p checker))
   2557     (insert (propertize " (automatically disabled) " 'face '(bold error)))
   2558     (insert-text-button "reset"
   2559                         'type 'flycheck-checker-reset-enabled
   2560                         'flycheck-data (list buffer checker))))
   2561   (when (eq checker (buffer-local-value 'flycheck-checker buffer))
   2562     (insert (propertize " (explicitly selected)" 'face 'bold)))
   2563   (when with-select
   2564     (princ "  ")
   2565     (insert-text-button "select"
   2566                         'type 'flycheck-checker-select
   2567                         'flycheck-data (list buffer checker)))
   2568   (princ "\n")
   2569   (let ((results (with-current-buffer buffer
   2570                    (append (flycheck-verify-generic-checker checker)
   2571                            (flycheck--verify-next-checkers checker)))))
   2572     (when with-mm
   2573       (with-current-buffer buffer
   2574         (let ((message-and-face
   2575                (if (flycheck-checker-supports-major-mode-p checker)
   2576                    (cons (format "`%s' supported" major-mode) 'success)
   2577                  (cons (format "`%s' not supported" major-mode) 'error))))
   2578           (push (flycheck-verification-result-new
   2579                  :label "major mode"
   2580                  :message (car message-and-face)
   2581                  :face (cdr message-and-face))
   2582                 results))))
   2583     (let* ((label-length
   2584             (seq-max (mapcar
   2585                       (lambda (res)
   2586                         (length (flycheck-verification-result-label res)))
   2587                       results)))
   2588            (message-column (+ 8 label-length)))
   2589       (dolist (result results)
   2590         (princ "    - ")
   2591         (princ (flycheck-verification-result-label result))
   2592         (princ ": ")
   2593         (princ (make-string (- message-column (current-column)) ?\ ))
   2594         (let ((message (flycheck-verification-result-message result))
   2595               (face (flycheck-verification-result-face result)))
   2596           ;; If face is nil, using propertize erases the face already contained
   2597           ;; by the message.  We don't want that, since this would remove the
   2598           ;; button face from the checker chain result.
   2599           (insert (if face (propertize message 'face face) message)))
   2600         (princ "\n"))))
   2601   (princ "\n"))
   2602 
   2603 (defun flycheck--get-next-checker-symbol (next)
   2604   "Get the checker symmbol of NEXT checker.
   2605 
   2606 NEXT should be either a cons (NEXT-CHECKER . LEVEL) or a
   2607 symbol."
   2608   (if (consp next) (cdr next) next))
   2609 
   2610 (defun flycheck-get-next-checkers (checker)
   2611   "Return the immediate next checkers of CHECKER.
   2612 
   2613 This is a list of checker symbols.  The error levels of the
   2614 `:next-checker' property are ignored."
   2615   (mapcar #'flycheck--get-next-checker-symbol
   2616           (flycheck-checker-get checker 'next-checkers)))
   2617 
   2618 (defun flycheck-all-next-checkers (checker)
   2619   "Return all checkers that may follow CHECKER.
   2620 
   2621 Return the transitive closure of the next-checker relation.  The
   2622 return value is a list of checkers, not including CHECKER."
   2623   (let ((next-checkers)
   2624         (visited)
   2625         (queue (list checker)))
   2626     (while queue
   2627       (let ((c (pop queue)))
   2628         (push c visited)
   2629         (dolist (n (flycheck-get-next-checkers c))
   2630           (push n next-checkers)
   2631           (unless (memq n visited)
   2632             (cl-pushnew n queue)))))
   2633     (seq-uniq next-checkers)))
   2634 
   2635 (defun flycheck--verify-next-checkers (checker)
   2636   "Return a verification result for the next checkers of CHECKER."
   2637   (when-let (next (flycheck-get-next-checkers checker))
   2638     (list
   2639      (flycheck-verification-result-new
   2640       :label "next checkers"
   2641       ;; We use `make-text-button' to preserve the button properties in the
   2642       ;; string
   2643       :message (mapconcat
   2644                 (lambda (checker)
   2645                   (make-text-button (symbol-name checker) nil
   2646                                     'type 'help-flycheck-checker-doc
   2647                                     'help-args (list checker)))
   2648                 next
   2649                 ", ")))))
   2650 
   2651 (defun flycheck--verify-print-header (desc buffer)
   2652   "Print a title with DESC for BUFFER in the current buffer.
   2653 
   2654 DESC is an arbitrary string containing a description, and BUFFER
   2655 is the buffer being verified.  The name and the major mode mode
   2656 of BUFFER are printed.
   2657 
   2658 DESC and information about BUFFER are printed in the current
   2659 buffer."
   2660   (princ desc)
   2661   (insert (propertize (buffer-name buffer) 'face 'bold))
   2662   (princ " in ")
   2663   (let ((mode (buffer-local-value 'major-mode buffer)))
   2664     (insert-button (symbol-name mode)
   2665                    'type 'help-function
   2666                    'help-args (list mode)))
   2667   (princ ":\n\n"))
   2668 
   2669 (defun flycheck--verify-print-footer (buffer)
   2670   "Print a footer for BUFFER in the current buffer.
   2671 
   2672 BUFFER is the buffer being verified."
   2673   (princ "Flycheck Mode is ")
   2674   (let ((enabled (buffer-local-value 'flycheck-mode buffer)))
   2675     (insert (propertize (if enabled "enabled" "disabled")
   2676                         'face (if enabled 'success '(warning bold)))))
   2677   (princ
   2678    (with-current-buffer buffer
   2679      ;; Use key binding state in the verified buffer to print the help.
   2680      (substitute-command-keys
   2681       ".  Use \\[universal-argument] \\[flycheck-disable-checker] \
   2682 to enable disabled checkers.")))
   2683   (save-excursion
   2684     (let ((end (point)))
   2685       (backward-paragraph)
   2686       (fill-region-as-paragraph (point) end)))
   2687 
   2688   (princ "\n\n--------------------\n\n")
   2689   (princ (format "Flycheck version: %s\n" (flycheck--pkg-version)))
   2690   (princ (format "Emacs version:    %s\n" emacs-version))
   2691   (princ (format "System:           %s\n" system-configuration))
   2692   (princ (format "Window system:    %S\n" window-system)))
   2693 
   2694 (define-derived-mode flycheck-verify-mode help-mode
   2695   "Flycheck verification"
   2696   "Major mode to display Flycheck verification results."
   2697   ;; `help-mode-finish' will restore `buffer-read-only'
   2698   (setq buffer-read-only nil))
   2699 
   2700 (defun flycheck-verify-checker (checker)
   2701   "Check whether a CHECKER can be used in this buffer.
   2702 
   2703 Show a buffer listing possible problems that prevent CHECKER from
   2704 being used for the current buffer.
   2705 
   2706 Note: Do not use this function to check whether a syntax checker
   2707 is applicable from Emacs Lisp code.  Use
   2708 `flycheck-may-use-checker' instead."
   2709   (interactive (list (flycheck-read-checker "Checker to verify: ")))
   2710   (unless (flycheck-valid-checker-p checker)
   2711     (user-error "%s is not a syntax checker" checker))
   2712 
   2713   ;; Save the buffer to make sure that all predicates are good
   2714   ;; FIXME: this may be surprising to users, with unintended side-effects.
   2715   (when (and (buffer-file-name) (buffer-modified-p))
   2716     (save-buffer))
   2717 
   2718   (let ((buffer (current-buffer)))
   2719     (with-help-window "*Flycheck checker*"
   2720       (with-current-buffer standard-output
   2721         (flycheck-verify-mode)
   2722         (flycheck--verify-print-header "Syntax checker in buffer " buffer)
   2723         (flycheck--verify-princ-checker checker buffer 'with-mm)
   2724         (if (with-current-buffer buffer (flycheck-may-use-checker checker))
   2725             (insert (propertize
   2726                      "Flycheck can use this syntax checker for this buffer.\n"
   2727                      'face 'success))
   2728           (insert (propertize
   2729                    "Flycheck cannot use this syntax checker for this buffer.\n"
   2730                    'face 'error)))
   2731         (insert "\n")
   2732         (flycheck--verify-print-footer buffer)))))
   2733 
   2734 (defun flycheck-verify-setup ()
   2735   "Check whether Flycheck can be used in this buffer.
   2736 
   2737 Display a new buffer listing all syntax checkers that could be
   2738 applicable in the current buffer.  For each syntax checkers,
   2739 possible problems are shown."
   2740   (interactive)
   2741   ;; Save to make sure checkers that only work on saved buffers will pass the
   2742   ;; verification
   2743   (when (and (buffer-file-name) (buffer-modified-p))
   2744     (save-buffer))
   2745 
   2746   (let* ((buffer (current-buffer))
   2747          (first-checker (flycheck-get-checker-for-buffer))
   2748          (valid-checkers
   2749           (remq first-checker
   2750                 (seq-filter #'flycheck-may-use-checker flycheck-checkers)))
   2751          (valid-next-checkers
   2752           (when first-checker
   2753             (seq-intersection valid-checkers
   2754                               (flycheck-all-next-checkers first-checker))))
   2755          (valid-remaining (seq-difference valid-checkers valid-next-checkers))
   2756          (other-checkers
   2757           (seq-difference (seq-filter #'flycheck-checker-supports-major-mode-p
   2758                                       flycheck-checkers)
   2759                           (cons first-checker valid-checkers))))
   2760 
   2761     ;; Print all applicable checkers for this buffer
   2762     (with-help-window "*Flycheck checkers*"
   2763       (with-current-buffer standard-output
   2764         (flycheck-verify-mode)
   2765 
   2766         (flycheck--verify-print-header "Syntax checkers for buffer " buffer)
   2767 
   2768         (if first-checker
   2769             (progn
   2770               (princ "First checker to run:\n\n")
   2771               (flycheck--verify-princ-checker first-checker buffer))
   2772           (insert (propertize
   2773                    "No checker to run in this buffer.\n\n"
   2774                    'face '(bold error))))
   2775 
   2776         (when valid-next-checkers
   2777           (princ
   2778            "Checkers that may run as part of the first checker's chain:\n\n")
   2779           (dolist (checker valid-next-checkers)
   2780             (flycheck--verify-princ-checker checker buffer)))
   2781 
   2782         (when valid-remaining
   2783           (princ "Checkers that could run if selected:\n\n")
   2784           (dolist (checker valid-remaining)
   2785             (flycheck--verify-princ-checker checker buffer nil 'with-select)))
   2786 
   2787         (when other-checkers
   2788           (princ
   2789            "Checkers that are compatible with this mode, \
   2790 but will not run until properly configured:\n\n")
   2791           (dolist (checker other-checkers)
   2792             (flycheck--verify-princ-checker checker buffer)))
   2793 
   2794         ;; If we have no checkers at all, that's worth mentioning
   2795         (unless (or first-checker valid-checkers other-checkers)
   2796           (insert (propertize
   2797                    "No checkers are available for this buffer.\n\n"
   2798                    'face '(bold error))))
   2799 
   2800         (let ((unregistered-checkers
   2801                (seq-difference (flycheck-defined-checkers) flycheck-checkers)))
   2802           (when unregistered-checkers
   2803             (insert (propertize
   2804                      "The following syntax checkers are not registered:\n"
   2805                      'face '(bold warning)))
   2806             (dolist (checker unregistered-checkers)
   2807               (princ "  - ")
   2808               (princ checker)
   2809               (princ "\n"))
   2810             (princ
   2811              "Try adding these syntax checkers to `flycheck-checkers'.\n\n")))
   2812 
   2813         (flycheck--verify-print-footer buffer)
   2814 
   2815         (setq-local revert-buffer-function
   2816                     (lambda (_ignore-auto _noconfirm)
   2817                       (with-current-buffer buffer (flycheck-verify-setup))))))))
   2818 
   2819 
   2820 ;;; Predicates for generic syntax checkers
   2821 (defun flycheck-buffer-saved-p (&optional buffer)
   2822   "Determine whether BUFFER is saved to a file.
   2823 
   2824 BUFFER is the buffer to check.  If omitted or nil, use the
   2825 current buffer as BUFFER.
   2826 
   2827 Return non-nil if the BUFFER is backed by a file, and not
   2828 modified, or nil otherwise."
   2829   (let ((file-name (buffer-file-name buffer)))
   2830     (and file-name (file-exists-p file-name) (not (buffer-modified-p buffer)))))
   2831 
   2832 
   2833 ;;; Extending generic checkers
   2834 (defun flycheck-remove-next-checker (checker next)
   2835   "After CHECKER remove a NEXT checker.
   2836 
   2837 CHECKER is a syntax checker symbol, from which to remove NEXT
   2838 checker.
   2839 
   2840 NEXT is a cons or a symbol, as documented in
   2841 `flycheck-add-next-checker'."
   2842   (unless (flycheck-valid-checker-p checker)
   2843     (error "%s is not a valid syntax checker" checker))
   2844   (let* ((next-symbol (flycheck--get-next-checker-symbol next)))
   2845     (setf
   2846      (flycheck-checker-get checker 'next-checkers)
   2847      (seq-remove
   2848       (lambda (next) (eq (flycheck--get-next-checker-symbol next) next-symbol))
   2849       (flycheck-checker-get checker 'next-checkers)))))
   2850 
   2851 (defun flycheck-add-next-checker (checker next &optional append)
   2852   "After CHECKER add a NEXT checker.
   2853 
   2854 CHECKER is a syntax checker symbol, to which to add NEXT checker.
   2855 
   2856 NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'.  NEXT-CHECKER is a
   2857 symbol denoting the syntax checker to run after CHECKER.  LEVEL
   2858 is an error level.  NEXT-CHECKER will only be used if there is no
   2859 current error whose level is more severe than LEVEL.  LEVEL may
   2860 also be t, in which case NEXT-CHECKER is used regardless of the
   2861 current errors.
   2862 
   2863 NEXT can also be a syntax checker symbol only, which is
   2864 equivalent to `(t . NEXT)'.
   2865 
   2866 NEXT-CHECKER is prepended before other next checkers, unless
   2867 APPEND is non-nil."
   2868   (unless (flycheck-valid-checker-p checker)
   2869     (error "%s is not a valid syntax checker" checker))
   2870   (flycheck-validate-next-checker next 'strict)
   2871   (flycheck-remove-next-checker checker next)
   2872   (let ((next-checkers (flycheck-checker-get checker 'next-checkers)))
   2873     (setf (flycheck-checker-get checker 'next-checkers)
   2874           (if append (append next-checkers (list next))
   2875             (cons next next-checkers)))))
   2876 
   2877 (defun flycheck-add-mode (checker mode)
   2878   "To CHECKER add a new major MODE.
   2879 
   2880 CHECKER and MODE are symbols denoting a syntax checker and a
   2881 major mode respectively.
   2882 
   2883 Add MODE to the `:modes' property of CHECKER, so that CHECKER
   2884 will be used in buffers with MODE."
   2885   (unless (flycheck-valid-checker-p checker)
   2886     (error "%s is not a valid syntax checker" checker))
   2887   (unless (symbolp mode)
   2888     (error "%s is not a symbol" mode))
   2889   (push mode (flycheck-checker-get checker 'modes)))
   2890 
   2891 
   2892 ;;; Generic syntax checks
   2893 (cl-defstruct (flycheck-syntax-check
   2894                (:constructor flycheck-syntax-check-new))
   2895   "Structure for storing syntax check state.
   2896 
   2897 Slots:
   2898 
   2899 `buffer'
   2900      The buffer being checked.
   2901 
   2902 `checker'
   2903      The syntax checker being used.
   2904 
   2905 `context'
   2906      The context object.
   2907 
   2908 `working-directory'
   2909      Working directory for the syntax checker. Serve as a value for
   2910      `default-directory' for a checker."
   2911   buffer checker context working-directory)
   2912 
   2913 (defun flycheck-syntax-check-start (syntax-check callback)
   2914   "Start a SYNTAX-CHECK with CALLBACK."
   2915   (let ((checker (flycheck-syntax-check-checker syntax-check))
   2916         (default-directory
   2917           (flycheck-syntax-check-working-directory syntax-check)))
   2918     (setf (flycheck-syntax-check-context syntax-check)
   2919           (funcall (flycheck-checker-get checker 'start) checker callback))))
   2920 
   2921 (defun flycheck-syntax-check-interrupt (syntax-check)
   2922   "Interrupt a SYNTAX-CHECK."
   2923   (let* ((checker (flycheck-syntax-check-checker syntax-check))
   2924          (interrupt-fn (flycheck-checker-get checker 'interrupt))
   2925          (context (flycheck-syntax-check-context syntax-check)))
   2926     (when interrupt-fn
   2927       (funcall interrupt-fn checker context))))
   2928 
   2929 
   2930 ;;; Syntax checking mode
   2931 
   2932 (defvar flycheck-mode-map
   2933   (let ((map (make-sparse-keymap)))
   2934     (define-key map flycheck-keymap-prefix flycheck-command-map)
   2935     ;; We place the menu under a custom menu key.  Since this menu key is not
   2936     ;; present in the menu of the global map, no top-level menu entry is added
   2937     ;; to the global menu bar.  However, it still appears on the mode line
   2938     ;; lighter.
   2939     (define-key map [menu-bar flycheck] flycheck-mode-menu-map)
   2940     map)
   2941   "Keymap of command `flycheck-mode'.")
   2942 
   2943 (defvar-local flycheck-old-next-error-function nil
   2944   "Remember the old `next-error-function'.")
   2945 
   2946 (defconst flycheck-hooks-alist
   2947   '(
   2948     ;; Handle events that may start automatic syntax checks
   2949     (after-save-hook        . flycheck-handle-save)
   2950     (after-change-functions . flycheck-handle-change)
   2951     ;; Handle events that may triggered pending deferred checks
   2952     (window-configuration-change-hook . flycheck-perform-deferred-syntax-check)
   2953     (post-command-hook                . flycheck-perform-deferred-syntax-check)
   2954     ;; Teardown Flycheck whenever the buffer state is about to get lost, to
   2955     ;; clean up temporary files and directories.
   2956     (kill-buffer-hook       . flycheck-teardown)
   2957     (change-major-mode-hook . flycheck-teardown)
   2958     (before-revert-hook     . flycheck-teardown)
   2959     ;; Update the error list if necessary
   2960     (post-command-hook . flycheck-error-list-update-source)
   2961     (post-command-hook . flycheck-error-list-highlight-errors)
   2962     ;; Display errors.  Show errors at point after commands (like movements) and
   2963     ;; when Emacs gets focus.  Cancel the display timer when Emacs looses focus
   2964     ;; (as there's no need to display errors if the user can't see them), and
   2965     ;; hide the error buffer (for large error messages) if necessary.  Note that
   2966     ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined
   2967     ;; hooks are perfectly ok we don't need a version guard here.  They'll just
   2968     ;; not work silently.
   2969     (post-command-hook . flycheck-maybe-display-error-at-point-soon)
   2970     (focus-in-hook     . flycheck-display-error-at-point-soon)
   2971     (focus-out-hook    . flycheck-cancel-error-display-error-at-point-timer)
   2972     (post-command-hook . flycheck-hide-error-buffer)
   2973     ;; Immediately show error popups when navigating to an error
   2974     (next-error-hook . flycheck-display-error-at-point))
   2975   "Hooks which Flycheck needs to hook in.
   2976 
   2977 The `car' of each pair is a hook variable, the `cdr' a function
   2978 to be added or removed from the hook variable if Flycheck mode is
   2979 enabled and disabled respectively.")
   2980 
   2981 ;;;###autoload
   2982 (define-minor-mode flycheck-mode
   2983   "Flycheck is a minor mode for on-the-fly syntax checking.
   2984 
   2985 In `flycheck-mode' the buffer is automatically syntax-checked
   2986 using the first suitable syntax checker from `flycheck-checkers'.
   2987 Use `flycheck-select-checker' to select a checker for the current
   2988 buffer manually.
   2989 
   2990 If you run into issues, use `\\[flycheck-verify-setup]' to get help.
   2991 
   2992 Flycheck supports many languages out of the box, and many
   2993 additional ones are available on MELPA.  Adding new ones is very
   2994 easy.  Complete documentation is available online at URL
   2995 `https://www.flycheck.org/en/latest/'.  Please report issues and
   2996 request features at URL `https://github.com/flycheck/flycheck'.
   2997 
   2998 Flycheck displays its status in the mode line.  In the default
   2999 configuration, it looks like this:
   3000 
   3001 `FlyC'     This buffer has not been checked yet.
   3002 `FlyC*'    Flycheck is running.  Expect results soon!
   3003 `FlyC:0'   Last check resulted in no errors and no warnings.
   3004 `FlyC:3|5' This buffer contains three errors and five warnings.
   3005            Use `\\[flycheck-list-errors]' to see the list.
   3006 `FlyC-'    Flycheck doesn't have a checker for this buffer.
   3007 
   3008 You may also see the following icons:
   3009 `FlyC!'    The checker crashed.
   3010 `FlyC.'    The last syntax check was manually interrupted.
   3011 `FlyC?'    The checker did something unexpected, like exiting with 1
   3012            but returning no errors.
   3013 
   3014 The following keybindings are available in `flycheck-mode':
   3015 
   3016 \\{flycheck-mode-map}
   3017 \(you can change the prefix by customizing
   3018 `flycheck-keymap-prefix')
   3019 
   3020 If called interactively, enable Flycheck mode if ARG is positive,
   3021 and disable it if ARG is zero or negative.  If called from Lisp,
   3022 also enable the mode if ARG is omitted or nil, and toggle it if
   3023 ARG is ‘toggle’; disable the mode otherwise."
   3024   :init-value nil
   3025   :keymap flycheck-mode-map
   3026   :lighter flycheck-mode-line
   3027   :after-hook (flycheck-buffer-automatically 'mode-enabled 'force-deferred)
   3028   (cond
   3029    (flycheck-mode
   3030     (flycheck-clear)
   3031 
   3032     (pcase-dolist (`(,hook . ,fn) (reverse flycheck-hooks-alist))
   3033       (add-hook hook fn nil 'local))
   3034 
   3035     (setq flycheck-old-next-error-function
   3036           (if flycheck-standard-error-navigation
   3037               next-error-function
   3038             :unset))
   3039     (when flycheck-standard-error-navigation
   3040       (setq next-error-function #'flycheck-next-error-function))
   3041 
   3042     ;; This hook must be added globally since otherwise we cannot
   3043     ;; detect a change from a buffer where Flycheck is enabled to a
   3044     ;; buffer where Flycheck is not enabled, and therefore cannot
   3045     ;; notice that there has been any change when the user switches
   3046     ;; back to the buffer where Flycheck is enabled.
   3047     (add-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
   3048    (t
   3049     (unless (eq flycheck-old-next-error-function :unset)
   3050       (setq next-error-function flycheck-old-next-error-function))
   3051 
   3052     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
   3053       (remove-hook hook fn 'local))
   3054 
   3055     (flycheck-teardown))))
   3056 
   3057 
   3058 ;;; Syntax checker selection for the current buffer
   3059 (defun flycheck-get-checker-for-buffer ()
   3060   "Find the checker for the current buffer.
   3061 
   3062 Use the selected checker for the current buffer, if any,
   3063 otherwise search for the best checker from `flycheck-checkers'.
   3064 
   3065 Return checker if there is a checker for the current buffer, or
   3066 nil otherwise."
   3067   (if flycheck-checker
   3068       (when (flycheck-may-use-checker flycheck-checker)
   3069         flycheck-checker)
   3070     (seq-find #'flycheck-may-use-checker flycheck-checkers)))
   3071 
   3072 (defun flycheck-get-next-checker-for-buffer (checker)
   3073   "Get the checker to run after CHECKER for the current buffer."
   3074   (let ((next (seq-find #'flycheck-may-use-next-checker
   3075                         (flycheck-checker-get checker 'next-checkers))))
   3076     (when next
   3077       (if (symbolp next) next (cdr next)))))
   3078 
   3079 (defun flycheck-select-checker (checker)
   3080   "Select CHECKER for the current buffer.
   3081 
   3082 CHECKER is a syntax checker symbol (see `flycheck-checkers') or
   3083 nil.  In the former case, use CHECKER for the current buffer,
   3084 otherwise deselect the current syntax checker (if any) and use
   3085 automatic checker selection via `flycheck-checkers'.
   3086 
   3087 If called interactively prompt for CHECKER.  With prefix arg
   3088 deselect the current syntax checker and enable automatic
   3089 selection again.
   3090 
   3091 Set `flycheck-checker' to CHECKER and automatically start a new
   3092 syntax check if the syntax checker changed.
   3093 
   3094 CHECKER will be used, even if it is not contained in
   3095 `flycheck-checkers', or if it is disabled via
   3096 `flycheck-disabled-checkers'."
   3097   (interactive
   3098    (if current-prefix-arg
   3099        (list nil)
   3100      (list (flycheck-read-checker "Select checker: "
   3101                                   (flycheck-get-checker-for-buffer)))))
   3102   (when (not (eq checker flycheck-checker))
   3103     (unless (or (not checker) (flycheck-may-use-checker checker))
   3104       (flycheck-verify-checker checker)
   3105       (user-error "Can't use syntax checker %S in this buffer" checker))
   3106     (setq flycheck-checker checker)
   3107     (when flycheck-mode
   3108       (flycheck-buffer))))
   3109 
   3110 (defun flycheck--toggle-checker (checker enable)
   3111   "Enable or disable CHECKER for the current buffer.
   3112 
   3113 If ENABLE, re-enable CHECKER by removing it from the buffer-local
   3114 value of `flycheck-disabled-checkers'.  Otherwise, add the syntax
   3115 checker to the buffer-local value of `flycheck-disabled-checkers'."
   3116   (cond
   3117    (enable
   3118     ;; We must use `remq' instead of `delq', because we must _not_ modify the
   3119     ;; list.  Otherwise we could potentially modify the global default value,
   3120     ;; in case the list is the global default.
   3121     (when (memq checker flycheck-disabled-checkers)
   3122       (setq flycheck-disabled-checkers
   3123             (remq checker flycheck-disabled-checkers)))
   3124     (when (memq checker flycheck--automatically-disabled-checkers)
   3125       (setq flycheck--automatically-disabled-checkers
   3126             (remq checker flycheck--automatically-disabled-checkers))))
   3127    (t (unless (memq checker flycheck-disabled-checkers)
   3128         (push checker flycheck-disabled-checkers)))))
   3129 
   3130 (defun flycheck-disable-checker (checker &optional enable)
   3131   "Interactively disable CHECKER for the current buffer.
   3132 
   3133 Prompt for a syntax checker to disable, and add the syntax
   3134 checker to the buffer-local value of
   3135 `flycheck-disabled-checkers'.
   3136 
   3137 With non-nil ENABLE or with prefix arg, prompt for a disabled
   3138 syntax checker and re-enable it by removing it from the
   3139 buffer-local value of `flycheck-disabled-checkers'."
   3140   (declare
   3141    (interactive-only "Directly set `flycheck-disabled-checkers' instead"))
   3142   (interactive
   3143    (let* ((enable current-prefix-arg)
   3144           (candidates (if enable
   3145                           (append flycheck-disabled-checkers
   3146                                   flycheck--automatically-disabled-checkers)
   3147                         flycheck-checkers))
   3148           (prompt (if enable "Enable syntax checker: "
   3149                     "Disable syntax checker: ")))
   3150      (when (and enable (not candidates))
   3151        (user-error "No syntax checkers disabled in this buffer"))
   3152      (list (flycheck-read-checker prompt nil nil candidates) enable)))
   3153   (unless checker
   3154     (user-error "No syntax checker given"))
   3155   (flycheck--toggle-checker checker enable)
   3156   (flycheck-buffer))
   3157 
   3158 
   3159 ;;; Syntax checks for the current buffer
   3160 (defvar-local flycheck-current-syntax-check nil
   3161   "The current syntax check in the this buffer.")
   3162 (put 'flycheck-current-syntax-check 'permanent-local t)
   3163 
   3164 (defun flycheck-start-current-syntax-check (checker)
   3165   "Start a syntax check in the current buffer with CHECKER.
   3166 
   3167 Set `flycheck-current-syntax-check' accordingly."
   3168   ;; Allocate the current syntax check *before* starting it.  This allows for
   3169   ;; synchronous checks, which call the status callback immediately in their
   3170   ;; start function.
   3171   (let* ((check
   3172           (flycheck-syntax-check-new
   3173            :buffer (current-buffer)
   3174            :checker checker
   3175            :context nil
   3176            :working-directory (flycheck-compute-working-directory checker)))
   3177          (callback (flycheck-buffer-status-callback check)))
   3178     (setq flycheck-current-syntax-check check)
   3179     (flycheck-report-status 'running)
   3180     (flycheck-syntax-check-start check callback)))
   3181 
   3182 (defun flycheck-running-p ()
   3183   "Determine whether a syntax check is running in the current buffer."
   3184   (not (null flycheck-current-syntax-check)))
   3185 
   3186 (defun flycheck-stop ()
   3187   "Stop any ongoing syntax check in the current buffer."
   3188   (when (flycheck-running-p)
   3189     (flycheck-syntax-check-interrupt flycheck-current-syntax-check)
   3190     ;; Remove the current syntax check, to reset Flycheck into a non-running
   3191     ;; state, and to make `flycheck-report-buffer-checker-status' ignore any
   3192     ;; status reports from the current syntax check.
   3193     (setq flycheck-current-syntax-check nil)
   3194     (flycheck-report-status 'interrupted)))
   3195 
   3196 (defun flycheck-buffer-status-callback (syntax-check)
   3197   "Create a status callback for SYNTAX-CHECK in the current buffer."
   3198   (lambda (&rest args)
   3199     (apply #'flycheck-report-buffer-checker-status
   3200            syntax-check args)))
   3201 
   3202 (defun flycheck-buffer ()
   3203   "Start checking syntax in the current buffer.
   3204 
   3205 Get a syntax checker for the current buffer with
   3206 `flycheck-get-checker-for-buffer', and start it."
   3207   (interactive)
   3208   (flycheck-clean-deferred-check)
   3209   (if flycheck-mode
   3210       (unless (flycheck-running-p)
   3211         ;; Clear error list and mark all overlays for deletion.  We do not
   3212         ;; delete all overlays immediately to avoid excessive re-displays and
   3213         ;; flickering, if the same errors gets highlighted again after the check
   3214         ;; completed.
   3215         (run-hooks 'flycheck-before-syntax-check-hook)
   3216         (flycheck-clear-errors)
   3217         (flycheck-mark-all-overlays-for-deletion)
   3218         (condition-case err
   3219             (let* ((checker (flycheck-get-checker-for-buffer)))
   3220               (if checker
   3221                   (flycheck-start-current-syntax-check checker)
   3222                 (flycheck-clear)
   3223                 (flycheck-report-status 'no-checker)))
   3224           (error
   3225            (flycheck-report-failed-syntax-check)
   3226            (signal (car err) (cdr err)))))
   3227     (user-error "Flycheck mode disabled")))
   3228 
   3229 (defun flycheck-report-buffer-checker-status
   3230     (syntax-check status &optional data)
   3231   "In BUFFER, report a SYNTAX-CHECK STATUS with DATA.
   3232 
   3233 SYNTAX-CHECK is the `flycheck-syntax-check' which reported
   3234 STATUS.  STATUS denotes the status of CHECKER, with an optional
   3235 DATA.  STATUS may be one of the following symbols:
   3236 
   3237 `errored'
   3238      The syntax checker has errored.  DATA is an optional error
   3239      message.
   3240 
   3241      This report finishes the current syntax check.
   3242 
   3243 `interrupted'
   3244      The syntax checker was interrupted.  DATA is ignored.
   3245 
   3246      This report finishes the current syntax check.
   3247 
   3248 `finished'
   3249      The syntax checker has finished with a proper error report
   3250      for the current buffer.  DATA is the (potentially empty)
   3251      list of `flycheck-error' objects reported by the syntax
   3252      check.
   3253 
   3254      This report finishes the current syntax check.
   3255 
   3256 `suspicious'
   3257      The syntax checker encountered a suspicious state, which the
   3258      user needs to be informed about.  DATA is an optional
   3259      message.
   3260 
   3261 A syntax checker _must_ report a status at least once with any
   3262 symbol that finishes the current syntax checker.  Otherwise
   3263 Flycheck gets stuck with the current syntax check.
   3264 
   3265 If CHECKER is not the currently used syntax checker in
   3266 `flycheck-current-syntax-check', the status report is largely
   3267 ignored.  Notably, any errors reported by the checker are
   3268 discarded."
   3269   (let ((buffer (flycheck-syntax-check-buffer syntax-check)))
   3270     ;; Ignore the status report if the buffer is gone, or if this syntax check
   3271     ;; isn't the current one in buffer (which can happen if this is an old
   3272     ;; report of an interrupted syntax check, and a new syntax check was started
   3273     ;; since this check was interrupted)
   3274     (when (and (buffer-live-p buffer)
   3275                (eq syntax-check
   3276                    (buffer-local-value 'flycheck-current-syntax-check buffer)))
   3277       (with-current-buffer buffer
   3278         (let ((checker (flycheck-syntax-check-checker syntax-check)))
   3279           (pcase status
   3280             ((or `errored `interrupted)
   3281              (flycheck-report-failed-syntax-check status)
   3282              (when (eq status 'errored)
   3283                ;; In case of error, show the error message
   3284                (message "Error from syntax checker %s: %s"
   3285                         checker (or data "UNKNOWN!"))))
   3286             (`suspicious
   3287              (when flycheck-mode
   3288                (message "Suspicious state from syntax checker %s: %s"
   3289                         checker (or data "UNKNOWN!")))
   3290              (flycheck-report-status 'suspicious))
   3291             (`finished
   3292              (when flycheck-mode
   3293                ;; Only report errors from the checker if Flycheck Mode is
   3294                ;; still enabled.
   3295                (flycheck-finish-current-syntax-check
   3296                 data
   3297                 (flycheck-syntax-check-working-directory syntax-check))))
   3298             (_
   3299              (error "Unknown status %s from syntax checker %s"
   3300                     status checker))))))))
   3301 
   3302 (defun flycheck-finish-current-syntax-check (errors working-dir)
   3303   "Finish the current syntax-check in the current buffer with ERRORS.
   3304 
   3305 ERRORS is a list of `flycheck-error' objects reported by the
   3306 current syntax check in `flycheck-current-syntax-check'.
   3307 
   3308 Report all ERRORS and potentially start any next syntax checkers.
   3309 
   3310 If the current syntax checker reported excessive errors, it is
   3311 disabled via `flycheck-disable-excessive-checker' for subsequent
   3312 syntax checks.
   3313 
   3314 Relative file names in ERRORS will be expanded relative to
   3315 WORKING-DIR."
   3316   (let* ((syntax-check flycheck-current-syntax-check)
   3317          (checker (flycheck-syntax-check-checker syntax-check))
   3318          (errors (flycheck-relevant-errors
   3319                   (flycheck-fill-and-expand-error-file-names
   3320                    (flycheck-filter-errors
   3321                     (flycheck-assert-error-list-p errors) checker)
   3322                    working-dir))))
   3323     (unless (flycheck-disable-excessive-checker checker errors)
   3324       (flycheck-report-current-errors errors))
   3325     (let ((next-checker (flycheck-get-next-checker-for-buffer checker)))
   3326       (if next-checker
   3327           (flycheck-start-current-syntax-check next-checker)
   3328         (setq flycheck-current-syntax-check nil)
   3329         (flycheck-report-status 'finished)
   3330         ;; Delete overlays only after the very last checker has run, to avoid
   3331         ;; flickering on intermediate re-displays
   3332         (flycheck-delete-marked-overlays)
   3333         (flycheck-error-list-refresh)
   3334         (run-hooks 'flycheck-after-syntax-check-hook)
   3335         (when (and flycheck-auto-display-errors-after-checking
   3336                    (eq (current-buffer) (window-buffer)))
   3337           (flycheck-display-error-at-point))
   3338         ;; Immediately try to run any pending deferred syntax check, which
   3339         ;; were triggered by intermediate automatic check event, to make sure
   3340         ;; that we quickly refine outdated error information
   3341         (flycheck-perform-deferred-syntax-check)))))
   3342 
   3343 (defun flycheck-disable-excessive-checker (checker errors)
   3344   "Disable CHECKER if it reported excessive ERRORS.
   3345 
   3346 If ERRORS has more items than `flycheck-checker-error-threshold',
   3347 add CHECKER to `flycheck--automatically-disabled-checkers', and
   3348 show a warning.
   3349 
   3350 Return t when CHECKER was disabled, or nil otherwise."
   3351   (when (and flycheck-checker-error-threshold
   3352              (> (length errors) flycheck-checker-error-threshold))
   3353     ;; Disable CHECKER for this buffer
   3354     ;; (`flycheck--automatically-disabled-checkers' is a local variable).
   3355     (lwarn '(flycheck syntax-checker) :warning
   3356            (substitute-command-keys
   3357             "Syntax checker %s reported too many errors (%s) and is disabled.
   3358 Use `\\[customize-variable] RET flycheck-checker-error-threshold' to
   3359 change the threshold or `\\[universal-argument] \
   3360 \\[flycheck-disable-checker]' to re-enable the checker.")
   3361            checker (length errors))
   3362     (push checker flycheck--automatically-disabled-checkers)
   3363     t))
   3364 
   3365 (defun flycheck-clear (&optional shall-interrupt)
   3366   "Clear all errors in the current buffer.
   3367 
   3368 With prefix arg or SHALL-INTERRUPT non-nil, also interrupt the
   3369 current syntax check."
   3370   (interactive "P")
   3371   (when shall-interrupt
   3372     (flycheck-stop))
   3373   (flycheck-delete-all-overlays)
   3374   (flycheck-clear-errors)
   3375   (flycheck-error-list-refresh)
   3376   (flycheck-hide-error-buffer))
   3377 
   3378 (defun flycheck--empty-variables ()
   3379   "Empty variables used by Flycheck."
   3380   (kill-local-variable 'flycheck--file-truename-cache)
   3381   (kill-local-variable 'flycheck--idle-trigger-timer)
   3382   (kill-local-variable 'flycheck--idle-trigger-conditions)
   3383   (kill-local-variable 'flycheck--last-error-display-tick))
   3384 
   3385 (defun flycheck-teardown (&optional ignore-global)
   3386   "Teardown Flycheck in the current buffer.
   3387 
   3388 Completely clear the whole Flycheck state.  Remove overlays, kill
   3389 running checks, and empty all variables used by Flycheck.
   3390 
   3391 Unless optional argument IGNORE-GLOBAL is non-nil, check to see
   3392 if no more Flycheck buffers remain (aside from the current
   3393 buffer), and if so then clean up global hooks."
   3394   (flycheck-safe-delete-temporaries)
   3395   (flycheck-stop)
   3396   (flycheck-clean-deferred-check)
   3397   (flycheck-clear)
   3398   (flycheck-cancel-error-display-error-at-point-timer)
   3399   (flycheck--clear-idle-trigger-timer)
   3400   (flycheck--empty-variables)
   3401   (unless (or ignore-global
   3402               (seq-some (lambda (buf)
   3403                           (and (not (equal buf (current-buffer)))
   3404                                (buffer-local-value 'flycheck-mode buf)))
   3405                         (buffer-list)))
   3406     (flycheck-global-teardown 'ignore-local)))
   3407 
   3408 
   3409 ;;; Automatic syntax checking in a buffer
   3410 (defun flycheck-may-check-automatically (&rest conditions)
   3411   "Determine whether the buffer may be checked under one of CONDITIONS.
   3412 
   3413 Read-only buffers may never be checked automatically.
   3414 
   3415 If CONDITIONS are given, determine whether syntax may be checked
   3416 under at least one of them, according to
   3417 `flycheck-check-syntax-automatically'."
   3418   (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p)))
   3419        (file-exists-p default-directory)
   3420        (or (not conditions)
   3421            (seq-some
   3422             (lambda (condition)
   3423               (memq condition flycheck-check-syntax-automatically))
   3424             conditions))))
   3425 
   3426 (defvar-local flycheck--idle-trigger-timer nil
   3427   "Timer used to trigger a syntax check after an idle delay.")
   3428 
   3429 (defvar-local flycheck--idle-trigger-conditions nil
   3430   "List of conditions under which an idle syntax check will be triggered.
   3431 This will be some subset of the allowable values for
   3432 `flycheck-check-syntax-automatically'.
   3433 
   3434 For example, if the user switches to a buffer and then makes an
   3435 edit, this list will have the values `idle-change' and
   3436 `idle-buffer-switch' in it, at least until the idle timer
   3437 expires.")
   3438 
   3439 (defun flycheck-buffer-automatically (&optional condition force-deferred)
   3440   "Automatically check syntax at CONDITION.
   3441 
   3442 Syntax is not checked if `flycheck-may-check-automatically'
   3443 returns nil for CONDITION.  (CONDITION may be a single condition
   3444 or a list of them.)
   3445 
   3446 The syntax check is deferred if FORCE-DEFERRED is non-nil, or if
   3447 `flycheck-must-defer-check' returns t."
   3448   (when (and flycheck-mode (if (listp condition)
   3449                                (apply #'flycheck-may-check-automatically
   3450                                       condition)
   3451                              (flycheck-may-check-automatically condition)))
   3452     (flycheck--clear-idle-trigger-timer)
   3453     (setq flycheck--idle-trigger-conditions nil)
   3454     (if (or force-deferred (flycheck-must-defer-check))
   3455         (flycheck-buffer-deferred)
   3456       (with-demoted-errors "Error while checking syntax automatically: %S"
   3457         (flycheck-buffer)))))
   3458 
   3459 (defun flycheck--clear-idle-trigger-timer ()
   3460   "Clear the idle trigger timer."
   3461   (when flycheck--idle-trigger-timer
   3462     (cancel-timer flycheck--idle-trigger-timer)
   3463     (setq flycheck--idle-trigger-timer nil)))
   3464 
   3465 (defun flycheck--handle-idle-trigger (buffer)
   3466   "Run a syntax check in BUFFER if appropriate.
   3467 This function is called by `flycheck--idle-trigger-timer'."
   3468   (let ((current-buffer (current-buffer)))
   3469     (when (buffer-live-p buffer)
   3470       (with-current-buffer buffer
   3471         (unless (or flycheck-buffer-switch-check-intermediate-buffers
   3472                     (eq buffer current-buffer))
   3473           (setq flycheck--idle-trigger-conditions
   3474                 (delq 'idle-buffer-switch
   3475                       flycheck--idle-trigger-conditions)))
   3476         (when flycheck--idle-trigger-conditions
   3477           (flycheck-buffer-automatically flycheck--idle-trigger-conditions)
   3478           (setq flycheck--idle-trigger-conditions nil))))))
   3479 
   3480 (defun flycheck-handle-change (beg end _len)
   3481   "Handle a buffer change between BEG and END.
   3482 
   3483 BEG and END mark the beginning and end of the change text.  _LEN
   3484 is ignored.
   3485 
   3486 Start a syntax check if a new line has been inserted into the
   3487 buffer."
   3488   ;; Save and restore the match data, as recommended in (elisp)Change Hooks
   3489   (save-match-data
   3490     (when flycheck-mode
   3491       (if (string-match-p (rx "\n") (buffer-substring beg end))
   3492           (flycheck-buffer-automatically 'new-line 'force-deferred)
   3493         (when (memq 'idle-change flycheck-check-syntax-automatically)
   3494           (flycheck--clear-idle-trigger-timer)
   3495           (cl-pushnew 'idle-change flycheck--idle-trigger-conditions)
   3496           (setq flycheck--idle-trigger-timer
   3497                 (run-at-time flycheck-idle-change-delay nil
   3498                              #'flycheck--handle-idle-trigger
   3499                              (current-buffer))))))))
   3500 
   3501 (defvar flycheck--last-buffer (current-buffer)
   3502   "The current buffer or the buffer that was previously current.
   3503 This is usually equal to the current buffer, unless the user just
   3504 switched buffers.  After a buffer switch, it is the previous
   3505 buffer.")
   3506 
   3507 (defun flycheck-handle-buffer-switch ()
   3508   "Handle a possible switch to another buffer.
   3509 
   3510 If a buffer switch actually happened, schedule a syntax check."
   3511   ;; Switching buffers here is weird, but unfortunately necessary.  It
   3512   ;; turns out that `with-temp-buffer' triggers
   3513   ;; `buffer-list-update-hook' twice, and the value of
   3514   ;; `current-buffer' is bogus in one of those triggers (the one just
   3515   ;; after the temp buffer is killed).  If we rely on the bogus value,
   3516   ;; Flycheck will think that the user is switching back and forth
   3517   ;; between different buffers during the `with-temp-buffer' call
   3518   ;; (note: two different normal buffers, not the current buffer and
   3519   ;; the temp buffer!), and that would trigger spurious syntax checks.
   3520   ;; It seems that reading (window-buffer) gets us the correct current
   3521   ;; buffer in all important real-life situations (although it doesn't
   3522   ;; necessarily catch uses of `set-buffer').
   3523   (with-current-buffer (window-buffer)
   3524     (unless (or (equal flycheck--last-buffer (current-buffer))
   3525                 ;; Don't bother keeping track of changes to and from
   3526                 ;; the minibuffer, as they will never require us to
   3527                 ;; run a syntax check.
   3528                 (minibufferp))
   3529       (setq flycheck--last-buffer (current-buffer))
   3530       (when (and flycheck-mode
   3531                  (memq 'idle-buffer-switch flycheck-check-syntax-automatically))
   3532         (flycheck--clear-idle-trigger-timer)
   3533         (cl-pushnew 'idle-buffer-switch flycheck--idle-trigger-conditions)
   3534         (setq flycheck--idle-trigger-timer
   3535               (run-at-time flycheck-idle-buffer-switch-delay nil
   3536                            #'flycheck--handle-idle-trigger
   3537                            (current-buffer)))))))
   3538 
   3539 (defun flycheck-handle-save ()
   3540   "Handle a save of the buffer."
   3541   (flycheck-buffer-automatically 'save))
   3542 
   3543 
   3544 ;;; Deferred syntax checking
   3545 (defvar-local flycheck-deferred-syntax-check nil
   3546   "If non-nil, a deferred syntax check is pending.")
   3547 
   3548 (defun flycheck-must-defer-check ()
   3549   "Determine whether the syntax check has to be deferred.
   3550 
   3551 A check has to be deferred if the buffer is not visible, or if the buffer is
   3552 currently being reverted.
   3553 
   3554 Return t if the check is to be deferred, or nil otherwise."
   3555   (or (not (get-buffer-window))
   3556       ;; We defer the syntax check if Flycheck is already running, to
   3557       ;; immediately start a new syntax check after the current one finished,
   3558       ;; because the result of the current check will most likely be outdated by
   3559       ;; the time it is finished.
   3560       (flycheck-running-p)
   3561       ;; We must defer checks while a buffer is being reverted, to avoid race
   3562       ;; conditions while the buffer contents are being restored.
   3563       revert-buffer-in-progress-p))
   3564 
   3565 (defun flycheck-deferred-check-p ()
   3566   "Determine whether the current buffer has a deferred check.
   3567 
   3568 Return t if so, or nil otherwise."
   3569   flycheck-deferred-syntax-check)
   3570 
   3571 (defun flycheck-buffer-deferred ()
   3572   "Defer syntax check for the current buffer."
   3573   (setq flycheck-deferred-syntax-check t))
   3574 
   3575 (defun flycheck-clean-deferred-check ()
   3576   "Clean a deferred syntax checking state."
   3577   (setq flycheck-deferred-syntax-check nil))
   3578 
   3579 (defun flycheck-perform-deferred-syntax-check ()
   3580   "Perform the deferred syntax check."
   3581   (when (flycheck-deferred-check-p)
   3582     (flycheck-clean-deferred-check)
   3583     (flycheck-buffer-automatically)))
   3584 
   3585 
   3586 ;;; Syntax checking in all buffers
   3587 (defun flycheck-may-enable-mode ()
   3588   "Determine whether Flycheck mode may be enabled.
   3589 
   3590 Flycheck mode is not enabled for
   3591 
   3592 - the minibuffer,
   3593 - `fundamental-mode'
   3594 - major modes whose `mode-class' property is `special',
   3595 - ephemeral buffers (see `flycheck-ephemeral-buffer-p'),
   3596 - encrypted buffers (see `flycheck-encrypted-buffer-p'),
   3597 - remote files (see `file-remote-p'),
   3598 - and major modes excluded by `flycheck-global-modes'.
   3599 
   3600 Return non-nil if Flycheck mode may be enabled, and nil
   3601 otherwise."
   3602   (and (pcase flycheck-global-modes
   3603          ;; Whether `major-mode' is disallowed by `flycheck-global-modes'
   3604          (`t t)
   3605          (`(not . ,modes) (not (memq major-mode modes)))
   3606          (modes (memq major-mode modes)))
   3607        (not (or (minibufferp)
   3608                 (eq major-mode 'fundamental-mode)
   3609                 (eq (get major-mode 'mode-class) 'special)
   3610                 (flycheck-ephemeral-buffer-p)
   3611                 (flycheck-encrypted-buffer-p)
   3612                 (and (buffer-file-name)
   3613                      (file-remote-p (buffer-file-name) 'method))))))
   3614 
   3615 (defun flycheck-mode-on-safe ()
   3616   "Enable command `flycheck-mode' if it is safe to do so.
   3617 
   3618 Command `flycheck-mode' is only enabled if
   3619 `flycheck-may-enable-mode' returns a non-nil result."
   3620   (when (flycheck-may-enable-mode)
   3621     (flycheck-mode)))
   3622 
   3623 ;;;###autoload
   3624 (define-globalized-minor-mode global-flycheck-mode flycheck-mode
   3625   flycheck-mode-on-safe
   3626   :init-value nil
   3627   :group 'flycheck)
   3628 
   3629 (defun flycheck-global-teardown (&optional ignore-local)
   3630   "Teardown Flycheck in all buffers.
   3631 
   3632 Completely clear the whole Flycheck state in all buffers, stop
   3633 all running checks, remove all temporary files, and empty all
   3634 variables of Flycheck.
   3635 
   3636 Also remove global hooks.  (If optional argument IGNORE-LOCAL is
   3637 non-nil, then only do this and skip per-buffer teardown.)"
   3638   (unless ignore-local
   3639     (dolist (buffer (buffer-list))
   3640       (when (buffer-live-p buffer)
   3641         (with-current-buffer buffer
   3642           (when flycheck-mode
   3643             (flycheck-teardown 'ignore-global))))))
   3644   (remove-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
   3645 
   3646 ;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any
   3647 ;; pending temporary files.
   3648 (add-hook 'kill-emacs-hook #'flycheck-global-teardown)
   3649 
   3650 
   3651 ;;; Errors from syntax checks
   3652 (cl-defstruct (flycheck-error
   3653                (:constructor nil)
   3654                (:constructor
   3655                 flycheck-error-new
   3656                 (&key
   3657                  line column end-line end-column
   3658                  buffer checker filename message level id group
   3659                  &aux (-end-line end-line) (-end-column end-column)))
   3660                (:constructor
   3661                 flycheck-error-new-at
   3662                 (line
   3663                  column
   3664                  &optional level message
   3665                  &key end-line end-column checker id group
   3666                  (filename (buffer-file-name)) (buffer (current-buffer))
   3667                  &aux (-end-line end-line) (-end-column end-column)))
   3668                (:constructor
   3669                 flycheck-error-new-at-pos
   3670                 (pos
   3671                  &optional level message
   3672                  &key end-pos checker id group
   3673                  (filename (buffer-file-name)) (buffer (current-buffer))
   3674                  &aux
   3675                  ((line . column)
   3676                   (if pos (flycheck-line-column-at-pos pos)
   3677                     '(nil . nil)))
   3678                  ((-end-line . -end-column)
   3679                   (if end-pos (flycheck-line-column-at-pos end-pos)
   3680                     '(nil . nil))))))
   3681   "Structure representing an error reported by a syntax checker.
   3682 Slots:
   3683 
   3684 `buffer'
   3685      The buffer that the error was reported for, as buffer object.
   3686 
   3687 `checker'
   3688      The syntax checker which reported this error, as symbol.
   3689 
   3690 `filename'
   3691      The file name the error refers to, as string.
   3692 
   3693 `line'
   3694      The line on which the error starts, as number.
   3695 
   3696 `column' (optional)
   3697      The column at which the error starts, as number.
   3698 
   3699      For compatibility with external tools and unlike Emacs
   3700      itself (e.g. in Compile Mode) Flycheck uses _1-based_
   3701      columns: The first character on a line is column 1.
   3702 
   3703      Occasionally some tools try to proactively adapt to Emacs
   3704      and emit 0-based columns automatically.  In these cases, the
   3705      columns must be adjusted for Flycheck, see
   3706      `flycheck-increment-error-columns'.
   3707 
   3708      If nil, the whole line is highlighted.
   3709 
   3710 `end-line' (optional)
   3711     The line on which the error ends.  If nil, this is computed according to
   3712     `flycheck-highlighting-mode'.
   3713 
   3714 `end-column'
   3715     The column at which the error ends.  If nil, this is computed according to
   3716     `flycheck-highlighting-mode'.  Error intervals are right-open: the
   3717     end-column points to the first character not included in the error.  For
   3718     example, 1:1 is an empty range. and in \"line-number-at-pos\", the range
   3719     6:12 covers the word \"number\".
   3720 
   3721 `message' (optional)
   3722      The error message as a string, if any.
   3723 
   3724 `level'
   3725      The error level, as either `info', `warning' or `error'.
   3726 
   3727 `id' (optional)
   3728      An ID identifying the kind of error.
   3729 
   3730 `group' (optional)
   3731      A symbol identifying the group the error belongs to.
   3732 
   3733      Some tools will emit multiple errors that relate to the same
   3734      issue (e.g., lifetime errors in Rust).  All related errors
   3735      collected by a checker should have the same `group` value,
   3736      in order to be able to present them to the user.
   3737 
   3738      See `flycheck-related-errors`."
   3739   buffer checker filename line column message level id group
   3740   ;; The fields below are at the end of the record to preserve backwards
   3741   ;; compatibility; see https://github.com/flycheck/flycheck/pull/1400 and
   3742   ;; https://lists.gnu.org/archive/html/emacs-devel/2018-07/msg00436.html
   3743   -end-line -end-column)
   3744 
   3745 ;; These accessors are defined for backwards compatibility
   3746 ;; FIXME: Clean up once package.el learns how to recompile dependencies.
   3747 
   3748 (defun flycheck-error-end-line (err)
   3749   "Return the end line of a Flycheck error ERR."
   3750   (condition-case nil (flycheck-error--end-line err)
   3751     (args-out-of-range nil)))
   3752 
   3753 (defun flycheck-error-end-column (err)
   3754   "Return the end column of a Flycheck error ERR."
   3755   (condition-case nil (flycheck-error--end-column err)
   3756     (args-out-of-range nil)))
   3757 
   3758 (defun flycheck-error--set-end-line (err line)
   3759   "Set the end line of a Flycheck error ERR to LINE."
   3760   (condition-case nil (setf (flycheck-error--end-line err) line)
   3761     (args-out-of-range nil)))
   3762 
   3763 (defun flycheck-error--set-end-column (err column)
   3764   "Set the end column of a Flycheck error ERR to COLUMN."
   3765   (condition-case nil (setf (flycheck-error--end-column err) column)
   3766     (args-out-of-range nil)))
   3767 
   3768 (gv-define-simple-setter flycheck-error-end-line
   3769                          flycheck-error--set-end-line)
   3770 (gv-define-simple-setter flycheck-error-end-column
   3771                          flycheck-error--set-end-column)
   3772 
   3773 (defmacro flycheck-error-with-buffer (err &rest forms)
   3774   "Switch to the buffer of ERR and evaluate FORMS.
   3775 
   3776 If the buffer of ERR is not live, FORMS are not evaluated."
   3777   (declare (indent 1) (debug t))
   3778   `(when (buffer-live-p (flycheck-error-buffer ,err))
   3779      (with-current-buffer (flycheck-error-buffer ,err)
   3780        ,@forms)))
   3781 
   3782 (defun flycheck--exact-region (err)
   3783   "Get the region of ERR, if ERR specifies a range.
   3784 
   3785 Return a cons cell `(BEG . END)'.  If the input range is empty,
   3786 it is expanded to cover at least one character so that END is
   3787 always greater than BEG.  If ERR doesn't specify an end-column
   3788 return nil."
   3789   (if-let* ((line (flycheck-error-line err))
   3790             (column (flycheck-error-column err))
   3791             (end-line (or (flycheck-error-end-line err) line))
   3792             (end-column (flycheck-error-end-column err)))
   3793       ;; Ignoring fields speeds up calls to `line-end-position'.
   3794       (let* ((inhibit-field-text-motion t)
   3795              (beg (flycheck-line-column-to-position line column))
   3796              (end (flycheck-line-column-to-position end-line end-column)))
   3797         (cond
   3798          ((< beg end) (cons beg end))
   3799          ((= end (point-max)) (cons (1- end) end))
   3800          (t (cons end (1+ end)))))))
   3801 
   3802 (defun flycheck--line-region (pos)
   3803   "Get the line region of position POS.
   3804 
   3805 Return a cons cell `(BEG . END)' where BEG is the first
   3806 non-whitespace character on the line ERR refers to, and END the
   3807 end of the line."
   3808   (save-excursion
   3809     (goto-char pos)
   3810     (forward-line 0)
   3811     (let ((bol (point))
   3812           (end (line-end-position)))
   3813       ;; Move to the beginning of this line's indentation, similar to
   3814       ;; `back-to-indentation'
   3815       (skip-syntax-forward " " end)
   3816       (backward-prefix-chars)
   3817       ;; If the current line is blank, highlight it in full; if it's
   3818       ;; empty, include the previous line break character(s) to have
   3819       ;; any region at all (when called with 0, `line-end-position'
   3820       ;; gives us the end of the previous line).
   3821       (cons (if (eolp) (if (= bol end) (line-end-position 0) bol) (point))
   3822             end))))
   3823 
   3824 (defun flycheck--column-region (pos)
   3825   "Get the column region of position POS.
   3826 
   3827 Return a cons cell `(BEG . END)' where BEG is the character
   3828 before the column, and END the actual column."
   3829   (save-excursion
   3830     (goto-char pos)
   3831     ;; (eobp): No enough lines in the buffer
   3832     (if (eobp) (cons (1- (point-max)) (point-max))
   3833       (cons pos (1+ pos)))))
   3834 
   3835 (defun flycheck-bounds-of-thing-at-point (thing pos)
   3836   "Get the region of THING at position POS.
   3837 
   3838 THING is a understood by `thing-at-point'.
   3839 
   3840 Return a cons cell `(BEG . END)' where BEG is the beginning of
   3841 the THING at the column, and END the end of the THING."
   3842   (save-excursion
   3843     (goto-char pos)
   3844     (bounds-of-thing-at-point thing)))
   3845 
   3846 (defun flycheck--approximate-region (err mode)
   3847   "Compute the region of ERR based on MODE and ERR's line and column."
   3848   ;; Ignoring fields speeds up calls to `line-end-position'.
   3849   (let* ((inhibit-field-text-motion t)
   3850          (line (flycheck-error-line err))
   3851          (column (flycheck-error-column err))
   3852          (beg (flycheck-line-column-to-position line (or column 1))))
   3853     (if (or (null column)
   3854             (eq mode 'lines))
   3855         (flycheck--line-region beg)
   3856       (or (pcase mode
   3857             (`symbols
   3858              ;; Ensure that we're on a word or symbol.  See
   3859              ;; https://github.com/flycheck/flycheck/issues/1519
   3860              (and (<= (point-min) beg) (< beg (point-max))
   3861                   (memq (char-syntax (char-after beg)) '(?w ?_))
   3862                   (flycheck-bounds-of-thing-at-point 'symbol beg)))
   3863             (`sexps
   3864              (flycheck-bounds-of-thing-at-point 'sexp beg)))
   3865           (flycheck--column-region beg)))))
   3866 
   3867 (defun flycheck-error-region-for-mode (err mode)
   3868   "Get the region of ERR for the highlighting MODE.
   3869 
   3870 ERR is a Flycheck error.  If its position is fully specified, use
   3871 that to compute a region; otherwise, use MODE, as documented in
   3872 `flycheck-highlighting-mode'.  If MODE is nil, signal an error."
   3873   (flycheck-error-with-buffer err
   3874     (save-restriction
   3875       (widen)
   3876       (or (flycheck--exact-region err)
   3877           (flycheck--approximate-region err mode)))))
   3878 
   3879 (defun flycheck-error-pos (err)
   3880   "Get the buffer position of ERR.
   3881 
   3882 ERR is a Flycheck error whose position to get.
   3883 
   3884 The error position is the error column, or the first
   3885 non-whitespace character of the error line, if ERR has no error column."
   3886   (car (flycheck-error-region-for-mode
   3887         err flycheck-highlighting-mode)))
   3888 
   3889 (defun flycheck-error-format-snippet (err &optional max-length)
   3890   "Extract the text that ERR refers to from the buffer.
   3891 
   3892 Newlines and blanks are replaced by single spaces.  If ERR
   3893 doesn't include an end-position, return nil.
   3894 
   3895 MAX-LENGTH is how many characters to read from the buffer, at
   3896 most.  It defaults to 20."
   3897   (flycheck-error-with-buffer err
   3898     (save-restriction
   3899       (widen)
   3900       (pcase (flycheck--exact-region err)
   3901         (`(,beg . ,end)
   3902          (truncate-string-to-width
   3903           (replace-regexp-in-string
   3904            "\\s-+" " " (buffer-substring beg (min end (point-max))))
   3905           (or max-length 20) nil nil t))))))
   3906 
   3907 (defun flycheck-error-format-message-and-id (err &optional include-snippet)
   3908   "Format the message and id of ERR as human-readable string.
   3909 
   3910 If INCLUDE-SNIPPET is non-nil, prepend the message with a snippet
   3911 of the text that the error applies to (such text can only be
   3912 determined if the error contains a full span, not just a
   3913 beginning position)."
   3914   (let* ((id (flycheck-error-id err))
   3915          (fname (flycheck-error-filename err))
   3916          (other-file-p (and fname (not (equal fname (buffer-file-name))))))
   3917     (concat (and other-file-p (format "In %S:\n" (file-relative-name fname)))
   3918             (and include-snippet
   3919                  (when-let* ((snippet (flycheck-error-format-snippet err)))
   3920                    (format-message "`%s': " snippet)))
   3921             (or (flycheck-error-message err)
   3922                 (format "Unknown %S" (flycheck-error-level err)))
   3923             (and id (format " [%s]" id)))))
   3924 
   3925 (defun flycheck-error-format-position (err)
   3926   "Format the position of ERR as a human-readable string."
   3927   (let ((line (flycheck-error-line err))
   3928         (column (flycheck-error-column err))
   3929         (end-line (flycheck-error-end-line err))
   3930         (end-column (flycheck-error-end-column err)))
   3931     (if (and line column)
   3932         (if (or (null end-line) (equal line end-line))
   3933             (if (or (null end-column) (equal column (1- end-column)))
   3934                 (format "%d:%d" line column)
   3935               (format "%d:%d-%d" line column end-column))
   3936           (format "(%d:%d)-(%d:%d)" line column end-line end-column))
   3937       (if (or (null end-line) (equal line end-line))
   3938           (format "%d" line)
   3939         (format "%d-%d" line end-line)))))
   3940 
   3941 (defun flycheck-error-format (err &optional with-file-name)
   3942   "Format ERR as human-readable string, optionally WITH-FILE-NAME.
   3943 
   3944 Return a string that represents the given ERR.  If WITH-FILE-NAME
   3945 is given and non-nil, include the file-name as well, otherwise
   3946 omit it."
   3947   (let* ((level (symbol-name (flycheck-error-level err)))
   3948          (checker (symbol-name (flycheck-error-checker err)))
   3949          (format `(,@(when with-file-name
   3950                        (list (flycheck-error-filename err) ":"))
   3951                    ,(flycheck-error-format-position err) ":"
   3952                    ,level ": "
   3953                    ,(flycheck-error-format-message-and-id err)
   3954                    " (" ,checker ")")))
   3955     (apply #'concat format)))
   3956 
   3957 (defun flycheck-error-< (err1 err2)
   3958   "Determine whether ERR1 is less than ERR2 by location."
   3959   (let ((l1 (flycheck-error-line err1))
   3960         (l2 (flycheck-error-line err2)))
   3961     (if (/= l1 l2)
   3962         (< l1 l2)
   3963       (let ((c1 (or (flycheck-error-column err1) 1))
   3964             (c2 (or (flycheck-error-column err2) 1)))
   3965         (if (/= c1 c2)
   3966             (< c1 c2)
   3967           (let ((el1 (or (flycheck-error-end-line err1) l1))
   3968                 (el2 (or (flycheck-error-end-line err2) l2)))
   3969             (if (/= el1 el2)
   3970                 (< el1 el2)
   3971               (let ((cl1 (or (flycheck-error-end-column err1) 1))
   3972                     (cl2 (or (flycheck-error-end-column err2) 1)))
   3973                 (< cl1 cl2)))))))))
   3974 
   3975 (defun flycheck-error-level-< (err1 err2)
   3976   "Determine whether ERR1 is less than ERR2 by error level.
   3977 
   3978 Like `flycheck-error-<', but compares by error level severity
   3979 first.  Levels of the same severity are compared by name."
   3980   (let* ((level1 (flycheck-error-level err1))
   3981          (level2 (flycheck-error-level err2))
   3982          (severity1 (flycheck-error-level-severity level1))
   3983          (severity2 (flycheck-error-level-severity level2)))
   3984     (cond
   3985      ((= severity1 severity2)
   3986       (if (string= level1 level2)
   3987           (flycheck-error-< err1 err2)
   3988         (string< level1 level2)))
   3989      (t (< severity1 severity2)))))
   3990 
   3991 (defun flycheck-assert-error-list-p (errors)
   3992   "Assert that all items in ERRORS are of `flycheck-error' type.
   3993 
   3994 Signal an error if any item in ERRORS is not a `flycheck-error'
   3995 object, as by `flycheck-error-p'.  Otherwise return ERRORS
   3996 again."
   3997   (unless (listp errors)
   3998     (signal 'wrong-type-argument (list 'listp errors)))
   3999   (dolist (err errors)
   4000     (unless (flycheck-error-p err)
   4001       (signal 'wrong-type-argument (list 'flycheck-error-p err))))
   4002   errors)
   4003 
   4004 
   4005 ;;; Errors in the current buffer
   4006 (defvar-local flycheck-current-errors nil
   4007   "A list of all errors and warnings in the current buffer.")
   4008 
   4009 (defun flycheck-report-current-errors (errors)
   4010   "Report ERRORS in the current buffer.
   4011 
   4012 Add ERRORS to `flycheck-current-errors' and process each error
   4013 with `flycheck-process-error-functions'."
   4014   (setq flycheck-current-errors (append errors flycheck-current-errors))
   4015   (overlay-recenter (point-max))
   4016   ;; We can't use `seq-sort-by' because it's not in Emacs 25's built-in `seq',
   4017   ;; and installing an updated version doesn't help (this is a package.el bug;
   4018   ;; see https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg01974.html).
   4019   (seq-do (lambda (err)
   4020             (run-hook-with-args-until-success 'flycheck-process-error-functions
   4021                                               err))
   4022           (seq-sort (lambda (e1 e2)
   4023                       (< (flycheck-error-line e1) (flycheck-error-line e2)))
   4024                     errors)))
   4025 
   4026 (defun flycheck-clear-errors ()
   4027   "Remove all error information from the current buffer."
   4028   (setq flycheck-current-errors nil)
   4029   (flycheck-report-status 'not-checked))
   4030 
   4031 (defun flycheck-fill-and-expand-error-file-names (errors directory)
   4032   "Fill and expand file names in ERRORS relative to DIRECTORY.
   4033 
   4034 Expand all file names of ERRORS against DIRECTORY.  If the file
   4035 name of an error is nil fill in the result of function
   4036 `buffer-file-name' in the current buffer.
   4037 
   4038 Return ERRORS, modified in-place."
   4039   (seq-do (lambda (err)
   4040             (setf (flycheck-error-filename err)
   4041                   (if-let (filename (flycheck-error-filename err))
   4042                       (expand-file-name filename directory)
   4043                     (buffer-file-name))))
   4044           errors)
   4045   errors)
   4046 
   4047 (defun flycheck-relevant-error-other-file-p (err)
   4048   "Determine whether ERR is a relevant error for another file."
   4049   (let ((file-name (flycheck-error-filename err)))
   4050     (and file-name
   4051          flycheck-relevant-error-other-file-show
   4052          (or (null buffer-file-name)
   4053              (not (flycheck-same-files-p buffer-file-name file-name)))
   4054          (<= (flycheck-error-level-severity
   4055               flycheck-relevant-error-other-file-minimum-level)
   4056              (flycheck-error-level-severity (flycheck-error-level err))))))
   4057 
   4058 (defun flycheck-relevant-error-p (err)
   4059   "Determine whether ERR is relevant for the current buffer.
   4060 
   4061 Return t if ERR may be shown for the current buffer, or nil
   4062 otherwise."
   4063   (flycheck-error-with-buffer err
   4064     (let ((file-name (flycheck-error-filename err))
   4065           (message (flycheck-error-message err)))
   4066       (and
   4067        (or
   4068         ;; Neither the error nor buffer have a file name
   4069         (and (not file-name) (not buffer-file-name))
   4070         ;; Both have files, and they match
   4071         (and buffer-file-name file-name
   4072              (flycheck-same-files-p file-name buffer-file-name))
   4073         ;; This is a significant error from another file
   4074         (flycheck-relevant-error-other-file-p err))
   4075        message
   4076        (not (string-empty-p message))
   4077        ;; Errors without line numbers are discarded.  If a linter
   4078        ;; reports relevant errors without line numbers, use
   4079        ;; `flycheck-fill-empty-line-numbers' as the checker's
   4080        ;; `:error-filter' to set them to line 0.
   4081        (flycheck-error-line err)))))
   4082 
   4083 (defun flycheck-relevant-errors (errors)
   4084   "Filter the relevant errors from ERRORS.
   4085 
   4086 Return a list of all errors that are relevant for their
   4087 corresponding buffer."
   4088   (seq-filter #'flycheck-relevant-error-p errors))
   4089 
   4090 (defun flycheck-related-errors (err &optional error-set)
   4091   "Get all the errors that are in the same group as ERR.
   4092 
   4093 Return a list of all errors (from ERROR-SET) that have the same
   4094 `flycheck-error-group' as ERR, including ERR itself.
   4095 
   4096 If ERROR-SET is nil, `flycheck-current-errors' is used instead."
   4097   (let ((group (flycheck-error-group err))
   4098         (checker (flycheck-error-checker err)))
   4099     (if group
   4100         (seq-filter (lambda (e)
   4101                       (and (eq (flycheck-error-checker e) checker)
   4102                            (eq (flycheck-error-group e) group)))
   4103                     (or error-set flycheck-current-errors))
   4104       (list err))))
   4105 
   4106 
   4107 ;;; Status reporting for the current buffer
   4108 (defvar-local flycheck-last-status-change 'not-checked
   4109   "The last status change in the current buffer.")
   4110 
   4111 (defun flycheck-report-failed-syntax-check (&optional status)
   4112   "Report a failed Flycheck syntax check with STATUS.
   4113 
   4114 STATUS is a status symbol for `flycheck-report-status',
   4115 defaulting to `errored'.
   4116 
   4117 Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and
   4118 report an error STATUS."
   4119   (flycheck-clear)
   4120   (setq flycheck-current-syntax-check nil)
   4121   (run-hooks 'flycheck-syntax-check-failed-hook)
   4122   (flycheck-report-status (or status 'errored)))
   4123 
   4124 (defun flycheck-report-status (status)
   4125   "Report Flycheck STATUS.
   4126 
   4127 STATUS is one of the following symbols:
   4128 
   4129 `not-checked'
   4130      The current buffer was not checked.
   4131 
   4132 `no-checker'
   4133      Automatic syntax checker selection did not find a suitable
   4134      syntax checker.
   4135 
   4136 `running'
   4137      A syntax check is now running in the current buffer.
   4138 
   4139 `errored'
   4140      The current syntax check has errored.
   4141 
   4142 `finished'
   4143      The current syntax check was finished normally.
   4144 
   4145 `interrupted'
   4146      The current syntax check was interrupted.
   4147 
   4148 `suspicious'
   4149      The last syntax check had a suspicious result.
   4150 
   4151 Set `flycheck-last-status-change' and call
   4152 `flycheck-status-changed-functions' with STATUS.  Afterwards
   4153 refresh the mode line."
   4154   (setq flycheck-last-status-change status)
   4155   (run-hook-with-args 'flycheck-status-changed-functions status)
   4156   (force-mode-line-update))
   4157 
   4158 (defun flycheck-mode-line-status-text (&optional status)
   4159   "Get a text describing STATUS for use in the mode line.
   4160 
   4161 STATUS defaults to `flycheck-last-status-change' if omitted or
   4162 nil."
   4163   (let* ((current-status (or status flycheck-last-status-change))
   4164          (indicator (pcase current-status
   4165                       (`not-checked "")
   4166                       (`no-checker "-")
   4167                       (`running "*")
   4168                       (`errored "!")
   4169                       (`finished
   4170                        (let-alist (flycheck-count-errors flycheck-current-errors)
   4171                          (if (or .error .warning)
   4172                              (format ":%s|%s" (or .error 0) (or .warning 0))
   4173                            flycheck-mode-success-indicator)))
   4174                       (`interrupted ".")
   4175                       (`suspicious "?")))
   4176          (face (when flycheck-mode-line-color
   4177                  (pcase current-status
   4178                    (`errored 'error)
   4179                    (`finished
   4180                     (let-alist (flycheck-count-errors flycheck-current-errors)
   4181                       (if (or .error .warning) 'error 'success))))))
   4182          (text (format " %s%s" flycheck-mode-line-prefix indicator)))
   4183     (when face
   4184       (setq text (propertize text 'face face)))
   4185     text))
   4186 
   4187 
   4188 ;;; Error levels
   4189 (defun flycheck-make-margin-spec (margin-str face)
   4190   "Make a display spec to indicate errors in the margins.
   4191 
   4192 Returns MARGIN-STR with FACE applied."
   4193   (propertize margin-str 'face `(,face default)))
   4194 
   4195 (defconst flycheck-default-margin-str "»"
   4196   "String used to indicate errors in the margins.")
   4197 
   4198 (defconst flycheck-default-margin-continuation-str "⋮"
   4199   "String used to indicate continuation lines in the margins.")
   4200 
   4201 ;;;###autoload
   4202 (defun flycheck-define-error-level (level &rest properties)
   4203   "Define a new error LEVEL with PROPERTIES.
   4204 
   4205 The following PROPERTIES constitute an error level:
   4206 
   4207 `:severity SEVERITY'
   4208      A number denoting the severity of this level.  The higher
   4209      the number, the more severe is this level compared to other
   4210      levels.  Defaults to 0; info is -10, warning is 10, and
   4211      error is 100.
   4212 
   4213      The severity is used by `flycheck-error-level-<' to
   4214      determine the ordering of errors according to their levels.
   4215 
   4216 `:compilation-level LEVEL'
   4217 
   4218      A number indicating the broad class of messages that errors
   4219      at this level belong to: one of 0 (info), 1 (warning), or
   4220      2 or nil (error).  Defaults to nil.
   4221 
   4222      This is used by `flycheck-checker-pattern-to-error-regexp'
   4223      to map error levels into `compilation-mode''s hierarchy and
   4224      to get proper highlighting of errors in `compilation-mode'.
   4225 
   4226 `:overlay-category CATEGORY'
   4227      A symbol denoting the overlay category to use for error
   4228      highlight overlays for this level.  See Info
   4229      node `(elisp)Overlay Properties' for more information about
   4230      overlay categories.
   4231 
   4232      A category for an error level overlay should at least define
   4233      the `face' property, for error highlighting.  Another useful
   4234      property for error level categories is `priority', to
   4235      influence the stacking of multiple error level overlays.
   4236 
   4237 `:fringe-bitmap BITMAPS'
   4238      A fringe bitmap symbol denoting the bitmap to use for fringe
   4239      indicators for this level, or a cons of two bitmaps (one for
   4240      narrow fringes and one for wide fringes).  See Info node
   4241      `(elisp)Fringe Bitmaps' for more information about fringe
   4242      bitmaps, including a list of built-in fringe bitmaps.
   4243 
   4244 `:fringe-face FACE'
   4245      A face symbol denoting the face to use for fringe indicators
   4246      for this level.
   4247 
   4248 `:margin-spec SPEC'
   4249      A display specification indicating what to display in the
   4250      margin when `flycheck-indication-mode' is `left-margin' or
   4251      `right-margin'.  See Info node `(elisp)Displaying in the
   4252      Margins'.  If omitted, Flycheck generates an image spec from
   4253      the fringe bitmap.
   4254 
   4255 `:error-list-face FACE'
   4256      A face symbol denoting the face to use for messages of this
   4257      level in the error list.  See `flycheck-list-errors'."
   4258   (declare (indent 1))
   4259   (setf (get level 'flycheck-error-level) t)
   4260   (setf (get level 'flycheck-error-severity)
   4261         (or (plist-get properties :severity) 0))
   4262   (setf (get level 'flycheck-compilation-level)
   4263         (plist-get properties :compilation-level))
   4264   (setf (get level 'flycheck-overlay-category)
   4265         (plist-get properties :overlay-category))
   4266   (setf (get level 'flycheck-fringe-bitmaps)
   4267         (let ((bitmap (plist-get properties :fringe-bitmap)))
   4268           (if (consp bitmap) bitmap (cons bitmap bitmap))))
   4269   ;; Kept for compatibility
   4270   (setf (get level 'flycheck-fringe-bitmap-double-arrow)
   4271         (car (get level 'flycheck-fringe-bitmaps)))
   4272   (setf (get level 'flycheck-fringe-face)
   4273         (plist-get properties :fringe-face))
   4274   (setf (get level 'flycheck-margin-spec)
   4275         (or (plist-get properties :margin-spec)
   4276             (flycheck-make-margin-spec
   4277              flycheck-default-margin-str
   4278              (or (get level 'flycheck-fringe-face) 'default))))
   4279   (setf (get level 'flycheck-margin-continuation)
   4280         (flycheck-make-margin-spec
   4281          flycheck-default-margin-continuation-str
   4282          (or (get level 'flycheck-fringe-face) 'default)))
   4283   (setf (get level 'flycheck-error-list-face)
   4284         (plist-get properties :error-list-face)))
   4285 
   4286 (defun flycheck-error-level-p (level)
   4287   "Determine whether LEVEL is a Flycheck error level."
   4288   (get level 'flycheck-error-level))
   4289 
   4290 (defun flycheck-error-level-severity (level)
   4291   "Get the numeric severity of LEVEL."
   4292   (or (get level 'flycheck-error-severity) 0))
   4293 
   4294 (defun flycheck-error-level-compilation-level (level)
   4295   "Get the compilation level for LEVEL."
   4296   (get level 'flycheck-compilation-level))
   4297 
   4298 (defun flycheck-error-level-overlay-category (level)
   4299   "Get the overlay category for LEVEL."
   4300   (get level 'flycheck-overlay-category))
   4301 
   4302 (defun flycheck-error-level-margin-spec (level)
   4303   "Get the margin spec for LEVEL."
   4304   (get level 'flycheck-margin-spec))
   4305 
   4306 (defun flycheck-error-level-margin-continuation-spec (level)
   4307   "Get the margin continuation spec for LEVEL."
   4308   (get level 'flycheck-margin-continuation))
   4309 
   4310 (defun flycheck-error-level-fringe-bitmap (level &optional hi-res)
   4311   "Get the fringe bitmap for LEVEL.
   4312 
   4313 Optional argument HI-RES non-nil means that the returned bitmap
   4314 will be the high resolution version."
   4315   (let ((bitmaps (get level 'flycheck-fringe-bitmaps)))
   4316     (if hi-res (cdr bitmaps) (car bitmaps))))
   4317 
   4318 (defun flycheck-error-level-fringe-face (level)
   4319   "Get the fringe face for LEVEL."
   4320   (get level 'flycheck-fringe-face))
   4321 
   4322 (defun flycheck-error-level-error-list-face (level)
   4323   "Get the error list face for LEVEL."
   4324   (get level 'flycheck-error-list-face))
   4325 
   4326 (defun flycheck-error-level-make-indicator (level side &optional continuation)
   4327   "Create the fringe or margin icon for LEVEL at SIDE.
   4328 
   4329 Return a propertized string that shows an indicator according
   4330 to LEVEL and the given fringe or margin SIDE.
   4331 
   4332 LEVEL is a Flycheck error level defined with
   4333 `flycheck-define-error-level', and SIDE is either `left-fringe',
   4334 `right-fringe', `left-margin', or `right-margin'.
   4335 
   4336 CONTINUATION indicates which fringe bitmap or margin spec to use:
   4337 either the `:fringe-bitmap' and `:margin-spec' properties of
   4338 LEVEL when CONTINUATION is nil or omitted, or bitmaps and specs
   4339 indicating an error spanning more than one line.
   4340 
   4341 Return a propertized string representing the fringe icon,
   4342 intended for use as `before-string' of an overlay to actually
   4343 show the indicator."
   4344   (propertize
   4345    "!" 'display
   4346    (pcase side
   4347      ((or `left-fringe `right-fringe)
   4348       (list side
   4349             (if continuation 'flycheck-fringe-bitmap-continuation
   4350               (let* ((fringe-width
   4351                       (pcase side
   4352                         (`left-fringe (car (window-fringes)))
   4353                         (`right-fringe (cadr (window-fringes)))))
   4354                      (high-res (>= fringe-width 16)))
   4355                 (flycheck-error-level-fringe-bitmap level high-res)))
   4356             (flycheck-error-level-fringe-face level)))
   4357      ((or `left-margin `right-margin)
   4358       `((margin ,side)
   4359         ,(or (if continuation
   4360                  (flycheck-error-level-margin-continuation-spec level)
   4361                (flycheck-error-level-margin-spec level))
   4362              "")))
   4363      (_ (error "Invalid fringe side: %S" side)))))
   4364 
   4365 (define-obsolete-function-alias
   4366   'flycheck-error-level-make-fringe-icon
   4367   'flycheck-error-level-make-indicator
   4368   "33")
   4369 
   4370 
   4371 ;;; Built-in error levels
   4372 (defconst flycheck-fringe-bitmap-double-arrow
   4373   [#b11011000
   4374    #b01101100
   4375    #b00110110
   4376    #b00011011
   4377    #b00110110
   4378    #b01101100
   4379    #b11011000]
   4380   "Bitmaps used to indicate errors in the left fringes.")
   4381 
   4382 (defconst flycheck-fringe-bitmap-double-left-arrow
   4383   [#b00011011
   4384    #b00110110
   4385    #b01101100
   4386    #b11011000
   4387    #b01101100
   4388    #b00110110
   4389    #b00011011]
   4390   "Bitmaps used to indicate errors in the right fringes.")
   4391 
   4392 (defconst flycheck-fringe-bitmap-double-arrow-hi-res
   4393   [#b1111001111000000
   4394    #b0111100111100000
   4395    #b0011110011110000
   4396    #b0001111001111000
   4397    #b0000111100111100
   4398    #b0000011110011110
   4399    #b0000011110011110
   4400    #b0000111100111100
   4401    #b0001111001111000
   4402    #b0011110011110000
   4403    #b0111100111100000
   4404    #b1111001111000000]
   4405   "High-resolution bitmap used to indicate errors in the left fringes.")
   4406 
   4407 (defconst flycheck-fringe-bitmap-double-left-arrow-hi-res
   4408   [#b0000001111001111
   4409    #b0000011110011110
   4410    #b0000111100111100
   4411    #b0001111001111000
   4412    #b0011110011110000
   4413    #b0111100111100000
   4414    #b0111100111100000
   4415    #b0011110011110000
   4416    #b0001111001111000
   4417    #b0000111100111100
   4418    #b0000011110011110
   4419    #b0000001111001111]
   4420   "High-resolution bitmap used to indicate errors in the right fringes.")
   4421 
   4422 (defconst flycheck-fringe-bitmap-continuation
   4423   [#b1000000010000000
   4424    #b0010000000100000
   4425    #b0000100000001000
   4426    #b0000001000000010]
   4427   "Bitmap used to indicate continuation lines in the fringes.")
   4428 
   4429 (when (fboundp 'define-fringe-bitmap) ;; #ifdef HAVE_WINDOW_SYSTEM
   4430   (define-fringe-bitmap
   4431     'flycheck-fringe-bitmap-double-arrow
   4432     flycheck-fringe-bitmap-double-arrow)
   4433   (define-fringe-bitmap
   4434     'flycheck-fringe-bitmap-double-arrow-hi-res
   4435     flycheck-fringe-bitmap-double-arrow-hi-res
   4436     nil 16)
   4437   (define-fringe-bitmap
   4438     'flycheck-fringe-bitmap-double-left-arrow
   4439     flycheck-fringe-bitmap-double-left-arrow)
   4440   (define-fringe-bitmap
   4441     'flycheck-fringe-bitmap-double-left-arrow-hi-res
   4442     flycheck-fringe-bitmap-double-left-arrow-hi-res
   4443     nil 16)
   4444   (define-fringe-bitmap
   4445     'flycheck-fringe-bitmap-continuation
   4446     flycheck-fringe-bitmap-continuation
   4447     nil 16 '(top repeat)))
   4448 
   4449 (defun flycheck-redefine-standard-error-levels
   4450     (&optional margin-str fringe-bitmap)
   4451   "Redefine Flycheck's standard error levels.
   4452 
   4453 This is useful to change the character drawn in the
   4454 margins (MARGIN-STR, a string) or the bitmap drawn in the
   4455 fringes (FRINGE-BITMAP, a fringe bitmap symbol or a cons of such
   4456 symbols, as in `flycheck-define-error-level')."
   4457   (unless margin-str
   4458     (setq margin-str flycheck-default-margin-str))
   4459 
   4460   (unless fringe-bitmap
   4461     (setq fringe-bitmap
   4462           (cons 'flycheck-fringe-bitmap-double-arrow
   4463                 'flycheck-fringe-bitmap-double-arrow-hi-res)))
   4464 
   4465   (setf (get 'flycheck-error-overlay 'face) 'flycheck-error)
   4466   (setf (get 'flycheck-error-overlay 'priority) 110)
   4467 
   4468   (flycheck-define-error-level 'error
   4469     :severity 100
   4470     :compilation-level 2
   4471     :overlay-category 'flycheck-error-overlay
   4472     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-error)
   4473     :fringe-bitmap fringe-bitmap
   4474     :fringe-face 'flycheck-fringe-error
   4475     :error-list-face 'flycheck-error-list-error)
   4476 
   4477   (setf (get 'flycheck-warning-overlay 'face) 'flycheck-warning)
   4478   (setf (get 'flycheck-warning-overlay 'priority) 100)
   4479 
   4480   (flycheck-define-error-level 'warning
   4481     :severity 10
   4482     :compilation-level 1
   4483     :overlay-category 'flycheck-warning-overlay
   4484     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-warning)
   4485     :fringe-bitmap fringe-bitmap
   4486     :fringe-face 'flycheck-fringe-warning
   4487     :error-list-face 'flycheck-error-list-warning)
   4488 
   4489   (setf (get 'flycheck-info-overlay 'face) 'flycheck-info)
   4490   (setf (get 'flycheck-info-overlay 'priority) 90)
   4491 
   4492   (flycheck-define-error-level 'info
   4493     :severity -10
   4494     :compilation-level 0
   4495     :overlay-category 'flycheck-info-overlay
   4496     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-info)
   4497     :fringe-bitmap fringe-bitmap
   4498     :fringe-face 'flycheck-fringe-info
   4499     :error-list-face 'flycheck-error-list-info))
   4500 
   4501 (flycheck-redefine-standard-error-levels)
   4502 
   4503 
   4504 ;;; Error filtering
   4505 (defun flycheck-filter-errors (errors checker)
   4506   "Filter ERRORS from CHECKER.
   4507 
   4508 Apply the error filter of CHECKER to ERRORs and return the
   4509 result.  If CHECKER has no error filter, fall back to
   4510 `flycheck-sanitize-errors'."
   4511   (let ((filter (or (flycheck-checker-get checker 'error-filter)
   4512                     #'flycheck-sanitize-errors)))
   4513     (funcall filter errors)))
   4514 
   4515 (defun flycheck-sanitize-errors (errors)
   4516   "Sanitize ERRORS.
   4517 
   4518 Sanitize ERRORS by trimming leading and trailing whitespace in
   4519 all error messages, and by replacing 0 columns and empty error
   4520 messages with nil.
   4521 
   4522 Returns sanitized ERRORS."
   4523   (dolist (err errors)
   4524     (flycheck-error-with-buffer err
   4525       (let ((message (flycheck-error-message err))
   4526             (id (flycheck-error-id err)))
   4527         (when message
   4528           (setq message (string-trim message))
   4529           (setf (flycheck-error-message err)
   4530                 (if (string-empty-p message) nil message)))
   4531         (when (and id (string-empty-p id))
   4532           (setf (flycheck-error-id err) nil))
   4533         (when (eq (flycheck-error-column err) 0)
   4534           (setf (flycheck-error-column err) nil))
   4535         (when (eq (flycheck-error-end-column err) 0)
   4536           (setf (flycheck-error-end-column err) nil)))))
   4537   errors)
   4538 
   4539 (defun flycheck-remove-error-file-names (file-name errors)
   4540   "Remove matching FILE-NAME from ERRORS.
   4541 
   4542 Use as `:error-filter' for syntax checkers that output faulty
   4543 filenames.  Flycheck will later fill in the buffer file name.
   4544 
   4545 Return ERRORS."
   4546   (seq-do (lambda (err)
   4547             (when (and (flycheck-error-filename err)
   4548                        (string= (flycheck-error-filename err) file-name))
   4549               (setf (flycheck-error-filename err) nil)))
   4550           errors)
   4551   errors)
   4552 
   4553 (defun flycheck-increment-error-columns (errors &optional offset)
   4554   "Increment all columns of ERRORS by OFFSET (default: 1).
   4555 
   4556   Use this as `:error-filter' if a syntax checker outputs 0-based
   4557   columns."
   4558   (setq offset (or offset 1)) ;; Emacs bug #31715
   4559   (seq-do (lambda (err)
   4560             (when (flycheck-error-column err)
   4561               (cl-incf (flycheck-error-column err) offset))
   4562             (when (flycheck-error-end-column err)
   4563               (cl-incf (flycheck-error-end-column err) offset)))
   4564           errors)
   4565   errors)
   4566 
   4567 (defun flycheck-collapse-error-message-whitespace (errors)
   4568   "Collapse whitespace in all messages of ERRORS.
   4569 
   4570 Return ERRORS."
   4571   (dolist (err errors)
   4572     (when-let (message (flycheck-error-message err))
   4573       (setf (flycheck-error-message err)
   4574             (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r")))
   4575                                       " " message 'fixed-case 'literal))))
   4576   errors)
   4577 
   4578 (defun flycheck-dedent-error-messages (errors)
   4579   "Dedent all messages of ERRORS.
   4580 
   4581 For each error in ERRORS, determine the indentation offset from
   4582 the leading whitespace of the first line, and dedent all further
   4583 lines accordingly.
   4584 
   4585 Return ERRORS, with in-place modifications."
   4586   (dolist (err errors)
   4587     (when-let (message (flycheck-error-message err))
   4588       (with-temp-buffer
   4589         (insert message)
   4590         ;; Determine the indentation offset
   4591         (goto-char (point-min))
   4592         (back-to-indentation)
   4593         (let* ((indent-offset (- (point) (point-min))))
   4594           ;; Now iterate over all lines and dedent each according to
   4595           ;; `indent-offset'
   4596           (while (not (eobp))
   4597             (back-to-indentation)
   4598             ;; If the current line starts with sufficient whitespace, delete the
   4599             ;; indentation offset.  Otherwise keep the line intact, as we might
   4600             ;; loose valuable information
   4601             (when (>= (- (point) (line-beginning-position)) indent-offset)
   4602               (delete-char (- indent-offset)))
   4603             (forward-line 1)))
   4604         (delete-trailing-whitespace (point-min) (point-max))
   4605         (setf (flycheck-error-message err)
   4606               (buffer-substring-no-properties (point-min) (point-max))))))
   4607   errors)
   4608 
   4609 (defun flycheck-fold-include-levels (errors sentinel-message)
   4610   "Fold levels of ERRORS from included files.
   4611 
   4612 ERRORS is a list of `flycheck-error' objects.  SENTINEL-MESSAGE
   4613 is a regular expression matched against the error message to
   4614 determine whether the error denotes errors from an included
   4615 file.  Alternatively, it is a function that is given an error and
   4616 shall return non-nil, if the error denotes errors from an
   4617 included file."
   4618   (unless (or (stringp sentinel-message) (functionp sentinel-message))
   4619     (error "Sentinel must be string or function: %S" sentinel-message))
   4620   (let ((sentinel (if (functionp sentinel-message)
   4621                       sentinel-message
   4622                     (lambda (err)
   4623                       (string-match-p sentinel-message
   4624                                       (flycheck-error-message err)))))
   4625         (remaining-errors errors))
   4626     (while remaining-errors
   4627       (let* ((current-error (pop remaining-errors)))
   4628         (when (funcall sentinel current-error)
   4629           ;; We found an error denoting errors in the included file:
   4630           ;; 1. process all subsequent errors until faulty include file is found
   4631           ;; 2. process again all subsequent errors until an error has the
   4632           ;;    current file name again
   4633           ;; 3. find the most severe error level
   4634           (let ((current-filename (flycheck-error-filename current-error))
   4635                 (current-level nil)
   4636                 (faulty-include-filename nil)
   4637                 (filename nil)
   4638                 (done (null remaining-errors)))
   4639 
   4640             (while (not done)
   4641               (setq filename (flycheck-error-filename (car remaining-errors)))
   4642               (unless faulty-include-filename
   4643                 (unless (string= filename current-filename)
   4644                   (setq faulty-include-filename filename)))
   4645 
   4646               (let* ((error-in-include (pop remaining-errors))
   4647                      (in-include-level (flycheck-error-level error-in-include)))
   4648                 (unless (funcall sentinel error-in-include)
   4649                   ;; Ignore nested "included file" errors, we are only
   4650                   ;; interested in real errors because these define our level
   4651                   (when (or (not current-level)
   4652                             (> (flycheck-error-level-severity in-include-level)
   4653                                (flycheck-error-level-severity current-level)))
   4654                     (setq current-level in-include-level))))
   4655 
   4656               (setq done (or (null remaining-errors)
   4657                              (and faulty-include-filename
   4658                                   (string= filename current-filename)))))
   4659 
   4660             (setf (flycheck-error-level current-error) current-level
   4661                   (flycheck-error-message current-error)
   4662                   (format "In include %s" faulty-include-filename))))))
   4663     errors))
   4664 
   4665 (defun flycheck-dequalify-error-ids (errors)
   4666   "De-qualify error ids in ERRORS.
   4667 
   4668 Remove all qualifications from error ids in ERRORS, by stripping
   4669 all leading dotted components from error IDs.  For instance, if
   4670 the error ID is com.foo.E100, replace it with E100.
   4671 
   4672 This error filter is mainly useful to simplify error IDs obtained
   4673 from parsing Checkstyle XML, which frequently has very verbose
   4674 IDs, that include the name of the tool."
   4675   (seq-do (lambda (err)
   4676             (let ((id (flycheck-error-id err)))
   4677               (when id
   4678                 (setf (flycheck-error-id err)
   4679                       (replace-regexp-in-string
   4680                        (rx string-start
   4681                            (group
   4682                             (optional (zero-or-more not-newline) "."))
   4683                            (one-or-more (not (any ".")))
   4684                            string-end)
   4685                        "" id 'fixedcase 'literal 1)))))
   4686           errors)
   4687   errors)
   4688 
   4689 (defun flycheck-remove-error-ids (errors)
   4690   "Remove all error ids from ERRORS."
   4691   (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors)
   4692   errors)
   4693 
   4694 (defun flycheck-fill-empty-line-numbers (errors)
   4695   "Set ERRORS without lines to line 0.
   4696 
   4697 Use as `:error-filter' for syntax checkers that output errors
   4698 without line numbers.
   4699 
   4700 Return ERRORS."
   4701   (seq-do (lambda (err)
   4702             (unless (flycheck-error-line err)
   4703               (setf (flycheck-error-line err) 0)))
   4704           errors)
   4705   errors)
   4706 
   4707 
   4708 ;;; Error analysis
   4709 (defun flycheck-count-errors (errors)
   4710   "Count the number of ERRORS, grouped by level.
   4711 
   4712 Return an alist, where each ITEM is a cons cell whose `car' is an
   4713 error level, and whose `cdr' is the number of errors of that
   4714 level."
   4715   (let (counts-by-level)
   4716     (dolist (err errors)
   4717       (let* ((level (flycheck-error-level err))
   4718              (item (assq level counts-by-level)))
   4719         (if item
   4720             (cl-incf (cdr item))
   4721           (push (cons level 1) counts-by-level))))
   4722     counts-by-level))
   4723 
   4724 (defun flycheck-has-max-errors-p (errors level)
   4725   "Check if there is no error in ERRORS more severe than LEVEL."
   4726   (let ((severity (flycheck-error-level-severity level)))
   4727     (seq-every-p (lambda (e) (<= (flycheck-error-level-severity
   4728                                   (flycheck-error-level e))
   4729                                  severity))
   4730                  errors)))
   4731 
   4732 (defun flycheck-has-max-current-errors-p (level)
   4733   "Check if there is no current error more severe than LEVEL."
   4734   (flycheck-has-max-errors-p flycheck-current-errors level))
   4735 
   4736 (defun flycheck-has-errors-p (errors level)
   4737   "Determine if there are any ERRORS with LEVEL."
   4738   (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors))
   4739 
   4740 (defun flycheck-has-current-errors-p (&optional level)
   4741   "Determine if the current buffer has errors with LEVEL.
   4742 
   4743 If LEVEL is omitted if the current buffer has any errors at all."
   4744   (if level
   4745       (flycheck-has-errors-p flycheck-current-errors level)
   4746     (and flycheck-current-errors t)))
   4747 
   4748 
   4749 ;;; Error overlays in the current buffer
   4750 (defvar-local flycheck--last-overlay-index 0
   4751   "Last index given to a Flycheck overlay.
   4752 
   4753 These indices are used to preserve error order (Emacs doesn't
   4754 preserve overlay order when calling `overlays-at').")
   4755 
   4756 (defun flycheck--next-overlay-index ()
   4757   "Compute the index to assign to a new Flycheck overlay."
   4758   (cl-incf flycheck--last-overlay-index))
   4759 
   4760 (defun flycheck--highlighting-style (err)
   4761   "Determine the highlighting style to apply to ERR.
   4762 
   4763 Styles are documented in `flycheck-highlighting-style'; this
   4764 functions resolves `conditional' style specifications."
   4765   (let* ((style flycheck-highlighting-style)
   4766          (first-line (flycheck-error-line err))
   4767          (end-line (or (flycheck-error-end-line err) first-line))
   4768          (nlines (- end-line first-line)))
   4769     (while (eq (car-safe style) 'conditional)
   4770       (pcase-let ((`(,threshold ,s1 ,s2) (cdr style)))
   4771         (setq style (if (< nlines threshold) s1 s2))))
   4772     (pcase style
   4773       (`(delimiters ,before ,after)
   4774        (when (characterp before)
   4775          (setq before (flycheck--make-highlighting-delimiter before)))
   4776        (when (characterp after)
   4777          (setq after (flycheck--make-highlighting-delimiter after)))
   4778        (setq style `(delimiters ,before ,after))))
   4779     style))
   4780 
   4781 (defun flycheck--setup-highlighting (err overlay)
   4782   "Apply properties to OVERLAY to highlight ERR."
   4783   (let ((level (flycheck-error-level err)))
   4784     (unless flycheck-highlighting-mode
   4785       ;; Erase the highlighting from the overlay if requested by the user
   4786       (setf (overlay-get overlay 'face) nil))
   4787     (when flycheck-indication-mode
   4788       (setf (overlay-get overlay 'before-string)
   4789             (flycheck-error-level-make-indicator
   4790              level flycheck-indication-mode))
   4791       (setf (overlay-get overlay 'line-prefix)
   4792             (flycheck-error-level-make-indicator
   4793              level flycheck-indication-mode t)))
   4794     (pcase (flycheck--highlighting-style err)
   4795       ((or `nil (guard (null flycheck-highlighting-mode)))
   4796        ;; Erase the highlighting
   4797        (setf (overlay-get overlay 'face) nil))
   4798       (`level-face)
   4799       (`(delimiters ,before ,after)
   4800        ;; Replace the highlighting with delimiters
   4801        (let* ((fringe-face (flycheck-error-level-fringe-face level))
   4802               (delim-face `(flycheck-error-delimiter ,fringe-face)))
   4803          (setf (overlay-get overlay 'face) 'flycheck-delimited-error)
   4804          (setf (overlay-get overlay 'before-string)
   4805                (concat (propertize before 'face delim-face)
   4806                        (or (overlay-get overlay 'before-string) "")))
   4807          (setf (overlay-get overlay 'after-string)
   4808                (propertize after 'face delim-face))))
   4809       (other (error "Unsupported highlighting style: %S" other)))))
   4810 
   4811 (defun flycheck-add-overlay (err)
   4812   "Add overlay for ERR.
   4813 
   4814 Return the created overlay."
   4815   ;; We must have a proper error region for the sake of fringe indication,
   4816   ;; error display and error navigation, even if the highlighting is disabled.
   4817   ;; We erase the highlighting later on in this case
   4818   (pcase-let* ((`(,beg . ,end)
   4819                 (if (flycheck-relevant-error-other-file-p err)
   4820                     ;; Display overlays for other-file errors on the first line
   4821                     (cons (point-min)
   4822                           (save-excursion (goto-char (point-min))
   4823                                           (line-end-position)))
   4824                   (flycheck-error-region-for-mode
   4825                    err (or flycheck-highlighting-mode 'lines))))
   4826                (overlay (make-overlay beg end))
   4827                (level (flycheck-error-level err))
   4828                (category (flycheck-error-level-overlay-category level))
   4829                (index (flycheck--next-overlay-index)))
   4830     (unless (flycheck-error-level-p level)
   4831       (error "Undefined error level: %S" level))
   4832     (setf (overlay-get overlay 'flycheck-error-index) index)
   4833     (setf (overlay-get overlay 'flycheck-overlay) t)
   4834     (setf (overlay-get overlay 'flycheck-error) err)
   4835     (setf (overlay-get overlay 'category) category)
   4836     (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo)
   4837     (flycheck--setup-highlighting err overlay)
   4838     overlay))
   4839 
   4840 (defun flycheck-help-echo (_window object pos)
   4841   "Construct a tooltip message.
   4842 
   4843 Most of the actual work is done by calling
   4844 `flycheck-help-echo-function' with the appropriate list of
   4845 errors.  Arguments WINDOW, OBJECT and POS are as described in
   4846 info node `(elisp)Special properties', as this function is
   4847 intended to be used as the \\='help-echo property of flycheck error
   4848 overlays."
   4849   (when-let (buf (cond ((bufferp object) object)
   4850                        ((overlayp object) (overlay-buffer object))))
   4851     (with-current-buffer buf
   4852       (when-let* ((fn flycheck-help-echo-function)
   4853                   (errs (flycheck-overlay-errors-at pos)))
   4854         (propertize (funcall fn errs) 'help-echo-inhibit-substitution t)))))
   4855 
   4856 (defun flycheck-help-echo-all-error-messages (errs)
   4857   "Concatenate error messages and ids from ERRS."
   4858   (pcase (delq nil errs) ;; FIXME why would errors be nil here?
   4859     (`(,err) ;; A single error
   4860      (flycheck-error-format-message-and-id err))
   4861     (_ ;; Zero or multiple errors
   4862      (mapconcat
   4863       (lambda (err)
   4864         (flycheck-error-format-message-and-id err 'include-snippet))
   4865       errs "\n"))))
   4866 
   4867 (defun flycheck-filter-overlays (overlays)
   4868   "Get all Flycheck overlays from OVERLAYS, in original order."
   4869   ;; The order of errors returned from overlays is not stable, so we sort
   4870   ;; them again using the internal index to guarantee errors are always
   4871   ;; displayed in the same order.
   4872   (seq-sort
   4873    ;; We can't use `seq-sort-by' here; see above
   4874    (lambda (o1 o2) (< (overlay-get o1 'flycheck-error-index)
   4875                       (overlay-get o2 'flycheck-error-index)))
   4876    (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays)))
   4877 
   4878 (defun flycheck-overlays-at (pos)
   4879   "Get all Flycheck overlays at POS."
   4880   (flycheck-filter-overlays (overlays-at pos)))
   4881 
   4882 (defun flycheck-overlays-in (beg end)
   4883   "Get all Flycheck overlays between BEG and END."
   4884   (flycheck-filter-overlays (overlays-in beg end)))
   4885 
   4886 (defun flycheck-overlay-errors-at (pos)
   4887   "Return a list of all flycheck errors overlaid at POS."
   4888   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
   4889            (flycheck-overlays-at pos)))
   4890 
   4891 (defun flycheck-overlay-errors-in (beg end)
   4892   "Return a list of all flycheck errors overlaid between BEG and END."
   4893   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
   4894            (flycheck-overlays-in beg end)))
   4895 
   4896 (defvar-local flycheck-overlays-to-delete nil
   4897   "Overlays mark for deletion after all syntax checks completed.")
   4898 (put 'flycheck-overlays-to-delete 'permanent-local t)
   4899 
   4900 (defun flycheck-delete-all-overlays ()
   4901   "Remove all flycheck overlays in the current buffer."
   4902   (overlay-recenter (point-max))
   4903   (flycheck-delete-marked-overlays)
   4904   (setq flycheck--last-overlay-index 0)
   4905   (save-restriction
   4906     (widen)
   4907     (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max)))))
   4908 
   4909 (defun flycheck-mark-all-overlays-for-deletion ()
   4910   "Mark all current overlays for deletion."
   4911   (setq flycheck-overlays-to-delete
   4912         (append (flycheck-overlays-in (point-min) (point-max))
   4913                 flycheck-overlays-to-delete)))
   4914 
   4915 (defun flycheck-delete-marked-overlays ()
   4916   "Delete all overlays marked for deletion."
   4917   (overlay-recenter (point-max))
   4918   (seq-do #'delete-overlay flycheck-overlays-to-delete)
   4919   (setq flycheck-overlays-to-delete nil))
   4920 
   4921 
   4922 ;;; Error navigation in the current buffer
   4923 (defun flycheck-error-level-interesting-at-pos-p (pos)
   4924   "Check if error severity at POS passes `flycheck-error-level-interesting-p'."
   4925   (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error)))
   4926 
   4927 (defun flycheck-error-level-interesting-p (err)
   4928   "Check if ERR severity is >= `flycheck-navigation-minimum-level'.
   4929 
   4930 ERR is also interesting (the function returns true) if there are
   4931 no errors as or more severe than `flycheck-navigation-minimum-level'."
   4932   (when (flycheck-error-p err)
   4933     (if-let (min-level flycheck-navigation-minimum-level)
   4934         (or (<= (flycheck-error-level-severity min-level)
   4935                 (flycheck-error-level-severity (flycheck-error-level err)))
   4936             (not (flycheck-has-current-errors-p min-level)))
   4937       t)))
   4938 
   4939 (defun flycheck-next-error-pos (n &optional reset)
   4940   "Get the position of the N-th next error.
   4941 
   4942 With negative N, get the position of the (-N)-th previous error
   4943 instead.  With non-nil RESET, search from `point-min', otherwise
   4944 search from the current point.
   4945 
   4946 Return the position of the next or previous error, or nil if
   4947 there is none.  If N is zero, return `point', or `point-min' if
   4948 RESET is non-nil."
   4949   (let ((n (or n 1))
   4950         (pos (if reset (point-min) (point))))
   4951     (if (>= n 0)
   4952         ;; Search forwards
   4953         (while (and pos (> n 0))
   4954           (setq n (1- n))
   4955           (when (get-char-property pos 'flycheck-error)
   4956             ;; Move beyond from the current error if any
   4957             (setq pos (next-single-char-property-change pos 'flycheck-error)))
   4958           (while (not (or (= pos (point-max))
   4959                           (flycheck-error-level-interesting-at-pos-p pos)))
   4960             ;; Scan for the next error
   4961             (setq pos (next-single-char-property-change pos 'flycheck-error)))
   4962           (when (and (= pos (point-max))
   4963                      (not (flycheck-error-level-interesting-at-pos-p pos)))
   4964             ;; If we reached the end of the buffer, but no error, we didn't find
   4965             ;; any
   4966             (setq pos nil)))
   4967       ;; Search backwards
   4968       (while (and pos (< n 0))
   4969         (setq n (1+ n))
   4970         ;; Loop until we find an error.  We need to check the position *before*
   4971         ;; the current one, because `previous-single-char-property-change'
   4972         ;; always moves to the position *of* the change.
   4973         (while (not (or (= pos (point-min))
   4974                         (flycheck-error-level-interesting-at-pos-p (1- pos))))
   4975           (setq pos (previous-single-char-property-change pos 'flycheck-error)))
   4976         (when (and (= pos (point-min))
   4977                    (not (flycheck-error-level-interesting-at-pos-p pos)))
   4978           ;; We didn't find any error.
   4979           (setq pos nil))
   4980         (when pos
   4981           ;; We found an error, so move to its beginning
   4982           (setq pos (previous-single-char-property-change pos
   4983                                                           'flycheck-error)))))
   4984     pos))
   4985 
   4986 (defun flycheck-next-error-function (n reset)
   4987   "Visit the N-th error from the current point.
   4988 
   4989 N is the number of errors to advance by, where a negative N
   4990 advances backwards.  With non-nil RESET, advance from the
   4991 beginning of the buffer, otherwise advance from the current
   4992 position.
   4993 
   4994 Intended for use with `next-error-function'."
   4995   (if-let* ((pos (flycheck-next-error-pos n reset))
   4996             (err (get-char-property pos 'flycheck-error)))
   4997       (flycheck-jump-to-error err)
   4998     (user-error "No more Flycheck errors")))
   4999 
   5000 (defun flycheck-next-error (&optional n reset)
   5001   "Visit the N-th error from the current point.
   5002 
   5003 N is the number of errors to advance by, where a negative N
   5004 advances backwards.  With non-nil RESET, advance from the
   5005 beginning of the buffer, otherwise advance from the current
   5006 position."
   5007   (interactive "P")
   5008   (when (consp n)
   5009     ;; Universal prefix argument means reset
   5010     (setq reset t n nil))
   5011   (flycheck-next-error-function n reset)
   5012   (flycheck-display-error-at-point))
   5013 
   5014 (defun flycheck-previous-error (&optional n)
   5015   "Visit the N-th previous error.
   5016 
   5017 If given, N specifies the number of errors to move backwards by.
   5018 If N is negative, move forwards instead."
   5019   (interactive "P")
   5020   (flycheck-next-error (- (or n 1))))
   5021 
   5022 (defun flycheck-first-error (&optional n)
   5023   "Visit the N-th error from beginning of the buffer.
   5024 
   5025 If given, N specifies the number of errors to move forward from
   5026 the beginning of the buffer."
   5027   (interactive "P")
   5028   (flycheck-next-error n 'reset))
   5029 
   5030 
   5031 ;;; Listing errors in buffers
   5032 (defconst flycheck-error-list-buffer "*Flycheck errors*"
   5033   "The name of the buffer to show error lists.")
   5034 
   5035 (defmacro flycheck-error-list-with-buffer (&rest body)
   5036   "Evaluate BODY in flycheck-error-list-buffer, if it exists."
   5037   (declare (indent 0) (debug t))
   5038   `(when (get-buffer flycheck-error-list-buffer)
   5039      (with-current-buffer flycheck-error-list-buffer
   5040        ,@body)))
   5041 
   5042 (defvar flycheck-error-list-mode-map
   5043   (let ((map (make-sparse-keymap)))
   5044     (define-key map (kbd "f") #'flycheck-error-list-set-filter)
   5045     (define-key map (kbd "F") #'flycheck-error-list-reset-filter)
   5046     (define-key map (kbd "n") #'flycheck-error-list-next-error)
   5047     (define-key map (kbd "p") #'flycheck-error-list-previous-error)
   5048     (define-key map (kbd "g") #'flycheck-error-list-check-source)
   5049     (define-key map (kbd "e") #'flycheck-error-list-explain-error)
   5050     (define-key map (kbd "RET") #'flycheck-error-list-goto-error)
   5051     map)
   5052   "The keymap of `flycheck-error-list-mode'.")
   5053 
   5054 (defun flycheck-error-list-make-last-column (message checker)
   5055   "Compute contents of the last error list cell.
   5056 
   5057 MESSAGE and CHECKER are displayed in a single column to allow the
   5058 message to stretch arbitrarily far."
   5059   (let ((checker-name (propertize (symbol-name checker)
   5060                                   'face 'flycheck-error-list-checker-name))
   5061         (message (propertize message
   5062                              'face 'flycheck-error-list-error-message)))
   5063     (format "%s (%s)" message checker-name)))
   5064 
   5065 (defconst flycheck-error-list-format
   5066   `[("File" 6)
   5067     ("Line" 5 flycheck-error-list-entry-< :right-align t)
   5068     ("Col" 3 nil :right-align t)
   5069     ("Level" 8 flycheck-error-list-entry-level-<)
   5070     ("ID" 6 t)
   5071     (,(flycheck-error-list-make-last-column "Message" 'Checker) 0 t)]
   5072   "Table format for the error list.")
   5073 
   5074 (defconst flycheck-error-list-padding 1
   5075   "Padding used in error list.")
   5076 
   5077 (defconst flycheck--error-list-msg-offset
   5078   (seq-reduce
   5079    (lambda (offset fmt)
   5080      (pcase-let* ((`(,_ ,width ,_ . ,props) fmt)
   5081                   (padding (or (plist-get props :pad-right) 1)))
   5082        (+ offset width padding)))
   5083    (seq-subseq flycheck-error-list-format 0 -1)
   5084    flycheck-error-list-padding)
   5085   "Amount of space to use in `flycheck-flush-multiline-message'.")
   5086 
   5087 (define-derived-mode flycheck-error-list-mode tabulated-list-mode
   5088   "Flycheck errors"
   5089   "Major mode for listing Flycheck errors.
   5090 
   5091 \\{flycheck-error-list-mode-map}"
   5092   (setq tabulated-list-format flycheck-error-list-format
   5093         ;; Sort by location initially
   5094         tabulated-list-sort-key (cons "Line" nil)
   5095         tabulated-list-padding flycheck-error-list-padding
   5096         tabulated-list-entries #'flycheck-error-list-entries
   5097         ;; `revert-buffer' updates the mode line for us, so all we need to do is
   5098         ;; set the corresponding mode line construct.
   5099         mode-line-buffer-identification flycheck-error-list-mode-line)
   5100   ;; See https://github.com/flycheck/flycheck/issues/1101
   5101   (setq-local truncate-string-ellipsis "…")
   5102   (tabulated-list-init-header))
   5103 
   5104 (defvar-local flycheck-error-list-source-buffer nil
   5105   "The current source buffer of the error list.")
   5106 ;; Needs to permanently local to preserve the source buffer across buffer
   5107 ;; reversions
   5108 (put 'flycheck-error-list-source-buffer 'permanent-local t)
   5109 
   5110 (defun flycheck-error-list-set-source (buffer)
   5111   "Set BUFFER as the source buffer of the error list."
   5112   (flycheck-error-list-with-buffer
   5113     (setq flycheck-error-list-source-buffer buffer)
   5114     (flycheck-error-list-refresh)))
   5115 
   5116 (defun flycheck-error-list-update-source ()
   5117   "Make the error list display errors from the current buffer.
   5118 
   5119 The update is skipped if the current buffer is the error list or
   5120 if the error list is already pointing to the current buffer."
   5121   (unless (memq (current-buffer)
   5122                 (list (get-buffer flycheck-error-list-buffer)
   5123                       (flycheck-error-list-with-buffer
   5124                         flycheck-error-list-source-buffer)))
   5125     (flycheck-error-list-set-source (current-buffer))))
   5126 
   5127 (defun flycheck-error-list-check-source ()
   5128   "Trigger a syntax check in the source buffer of the error list."
   5129   (interactive)
   5130   (let ((buffer (get-buffer flycheck-error-list-source-buffer)))
   5131     (when (buffer-live-p buffer)
   5132       (with-current-buffer buffer
   5133         (flycheck-buffer)))))
   5134 
   5135 (define-button-type 'flycheck-error-list
   5136   'action #'flycheck-error-list-goto-error
   5137   'help-echo "mouse-1, RET: goto error"
   5138   'face nil)
   5139 
   5140 (define-button-type 'flycheck-error-list-explain-error
   5141   'action #'flycheck-error-list-explain-error
   5142   'help-echo "mouse-1, RET: explain error")
   5143 
   5144 (defsubst flycheck-error-list-make-cell (text &optional face help-echo type)
   5145   "Make an error list cell with TEXT and FACE.
   5146 
   5147 If FACE is nil don't set a FACE on TEXT.  If TEXT already has
   5148 face properties, do not specify a FACE.  Note though, that if
   5149 TEXT gets truncated it will not inherit any previous face
   5150 properties.  If you expect TEXT to be truncated in the error
   5151 list, do specify a FACE explicitly!
   5152 
   5153 If HELP-ECHO is non-nil, set a help-echo property on TEXT, with
   5154 value HELP-ECHO.  This is convenient if you expect TEXT to be
   5155 truncated.
   5156 
   5157 The cell will have the type TYPE unless TYPE is nil, and the
   5158 default type `flycheck-error-list' will be used instead."
   5159   (append (list text 'type (if type type
   5160                              'flycheck-error-list))
   5161           (and face (list 'face face))
   5162           (and help-echo (list 'help-echo help-echo))))
   5163 
   5164 (defsubst flycheck-error-list-make-number-cell (number face)
   5165   "Make a table cell for a NUMBER with FACE.
   5166 
   5167 Convert NUMBER to string, fontify it with FACE and return the
   5168 string with attached text properties."
   5169   (flycheck-error-list-make-cell
   5170    (if (numberp number) (number-to-string number) "")
   5171    face))
   5172 
   5173 (defun flycheck-error-list-make-entry (error)
   5174   "Make a table cell for the given ERROR.
   5175 
   5176 Return a list with the contents of the table cell."
   5177   (let* ((level (flycheck-error-level error))
   5178          (level-face (flycheck-error-level-error-list-face level))
   5179          (filename (flycheck-error-filename error))
   5180          (line (flycheck-error-line error))
   5181          (column (flycheck-error-column error))
   5182          (message (or (flycheck-error-message error)
   5183                       (format "Unknown %S" level)))
   5184          (flushed-msg (flycheck-flush-multiline-message message))
   5185          (id (flycheck-error-id error))
   5186          (id-str (if id (format "%s" id) ""))
   5187          (checker (flycheck-error-checker error))
   5188          (msg-and-checker
   5189           (flycheck-error-list-make-last-column flushed-msg checker))
   5190          (explainer (flycheck-checker-get checker 'error-explainer)))
   5191     (list error
   5192           (vector (flycheck-error-list-make-cell
   5193                    (if filename
   5194                        (file-name-nondirectory filename)
   5195                      "")
   5196                    'flycheck-error-list-filename)
   5197                   (flycheck-error-list-make-number-cell
   5198                    line 'flycheck-error-list-line-number)
   5199                   (flycheck-error-list-make-number-cell
   5200                    column 'flycheck-error-list-column-number)
   5201                   (flycheck-error-list-make-cell
   5202                    (symbol-name (flycheck-error-level error)) level-face)
   5203                   ;; Error ID use a different face when an error-explainer is
   5204                   ;; present
   5205                   (flycheck-error-list-make-cell
   5206                    id-str (if explainer 'flycheck-error-list-id-with-explainer
   5207                             'flycheck-error-list-id)
   5208                    id-str 'flycheck-error-list-explain-error)
   5209                   (flycheck-error-list-make-cell
   5210                    msg-and-checker nil msg-and-checker)))))
   5211 
   5212 (defun flycheck-flush-multiline-message (msg)
   5213   "Prepare error message MSG for display in the error list.
   5214 
   5215 Prepend all lines of MSG except the first with enough space to
   5216 ensure that they line up properly once the message is displayed."
   5217   (let* ((spc-spec `(space . (:width ,flycheck--error-list-msg-offset)))
   5218          (spc (propertize " " 'display spc-spec))
   5219          (rep (concat "\\1" spc "\\2")))
   5220     (replace-regexp-in-string "\\([\r\n]+\\)\\(.\\)" rep msg)))
   5221 
   5222 (defun flycheck-error-list-current-errors ()
   5223   "Read the list of errors in `flycheck-error-list-source-buffer'."
   5224   (when (buffer-live-p flycheck-error-list-source-buffer)
   5225     (buffer-local-value 'flycheck-current-errors
   5226                         flycheck-error-list-source-buffer)))
   5227 
   5228 (defun flycheck-error-list-entries ()
   5229   "Create the entries for the error list."
   5230   (when-let* ((errors (flycheck-error-list-current-errors))
   5231               (filtered (flycheck-error-list-apply-filter errors)))
   5232     (seq-map #'flycheck-error-list-make-entry filtered)))
   5233 
   5234 (defun flycheck-error-list-entry-< (entry1 entry2)
   5235   "Determine whether ENTRY1 is before ENTRY2 by location.
   5236 
   5237 See `flycheck-error-<'."
   5238   (flycheck-error-< (car entry1) (car entry2)))
   5239 
   5240 (defun flycheck-error-list-entry-level-< (entry1 entry2)
   5241   "Determine whether ENTRY1 is before ENTRY2 by level.
   5242 
   5243 See `flycheck-error-level-<'."
   5244   (not (flycheck-error-level-< (car entry1) (car entry2))))
   5245 
   5246 (defvar flycheck-error-list-mode-line-map
   5247   (let ((map (make-sparse-keymap)))
   5248     (define-key map [mode-line mouse-1]
   5249       #'flycheck-error-list-mouse-switch-to-source)
   5250     map)
   5251   "Keymap for error list mode line.")
   5252 
   5253 (defun flycheck-error-list-propertized-source-name ()
   5254   "Get the name of the current source buffer for the mode line.
   5255 
   5256 Propertize the name of the current source buffer for use in the
   5257 mode line indication of `flycheck-error-list-mode'."
   5258   (let ((name (replace-regexp-in-string
   5259                (rx "%") "%%"
   5260                (buffer-name flycheck-error-list-source-buffer)
   5261                'fixed-case 'literal)))
   5262     (propertize name 'face 'mode-line-buffer-id
   5263                 'mouse-face 'mode-line-highlight
   5264                 'help-echo "mouse-1: switch to source"
   5265                 'local-map flycheck-error-list-mode-line-map)))
   5266 
   5267 (defun flycheck-error-list-mouse-switch-to-source (event)
   5268   "Switch to the error list source buffer of the EVENT window."
   5269   (interactive "e")
   5270   (save-selected-window
   5271     (when (eventp event)
   5272       (select-window (posn-window (event-start event))))
   5273     (when (buffer-live-p flycheck-error-list-source-buffer)
   5274       (switch-to-buffer flycheck-error-list-source-buffer))))
   5275 
   5276 (defun flycheck-get-error-list-window-list (&optional all-frames)
   5277   "Get all windows displaying the error list.
   5278 
   5279 ALL-FRAMES specifies the frames to consider, as in
   5280 `get-buffer-window-list'."
   5281   (when-let (buf (get-buffer flycheck-error-list-buffer))
   5282     (get-buffer-window-list buf nil all-frames)))
   5283 
   5284 (defun flycheck-get-error-list-window (&optional all-frames)
   5285   "Get a window displaying the error list, or nil if none.
   5286 
   5287 ALL-FRAMES specifies the frames to consider, as in
   5288 `get-buffer-window'."
   5289   (when-let (buf (get-buffer flycheck-error-list-buffer))
   5290     (get-buffer-window buf all-frames)))
   5291 
   5292 (defun flycheck-error-list-recenter-at (pos)
   5293   "Recenter the error list at POS."
   5294   (dolist (window (flycheck-get-error-list-window-list t))
   5295     (with-selected-window window
   5296       (goto-char pos)
   5297       (let ((recenter-redisplay nil))
   5298         (recenter)))))
   5299 
   5300 (defun flycheck-error-list-refresh ()
   5301   "Refresh the current error list.
   5302 
   5303 Add all errors currently reported for the current
   5304 `flycheck-error-list-source-buffer', and recenter the error
   5305 list."
   5306   ;; We only refresh the error list, when it is visible in a window, and we
   5307   ;; select this window while reverting, because Tabulated List mode attempts to
   5308   ;; recenter the error at the old location, so it must have the proper window
   5309   ;; selected.
   5310   (when-let (window (flycheck-get-error-list-window t))
   5311     (with-selected-window window
   5312       (revert-buffer))
   5313     (run-hooks 'flycheck-error-list-after-refresh-hook)
   5314     (let ((preserve-pos (eq (current-buffer)
   5315                             (get-buffer flycheck-error-list-buffer))))
   5316       ;; If the error list is the current buffer, don't recenter when
   5317       ;; highlighting
   5318       (flycheck-error-list-highlight-errors preserve-pos))))
   5319 
   5320 (defun flycheck-error-list-mode-line-filter-indicator ()
   5321   "Create a string representing the current error list filter."
   5322   (if flycheck-error-list-minimum-level
   5323       (format " [>= %s]" flycheck-error-list-minimum-level)
   5324     ""))
   5325 
   5326 (defun flycheck-error-list-set-filter (level)
   5327   "Restrict the error list to errors at level LEVEL or higher.
   5328 
   5329 LEVEL is either an error level symbol, or nil, to remove the filter."
   5330   (interactive
   5331    (list (flycheck-read-error-level
   5332           "Minimum error level (errors at lower levels will be hidden): ")))
   5333   (when (and level (not (flycheck-error-level-p level)))
   5334     (user-error "Invalid level: %s" level))
   5335   (flycheck-error-list-with-buffer
   5336     (setq-local flycheck-error-list-minimum-level level)
   5337     (force-mode-line-update)
   5338     (flycheck-error-list-refresh)
   5339     (flycheck-error-list-recenter-at (point-min))))
   5340 
   5341 (defun flycheck-error-list-reset-filter (&optional refresh)
   5342   "Remove local error filters and reset to the default filter.
   5343 
   5344 Interactively, or with non-nil REFRESH, refresh the error list."
   5345   (interactive '(t))
   5346   (flycheck-error-list-with-buffer
   5347     (kill-local-variable 'flycheck-error-list-minimum-level)
   5348     (when refresh
   5349       (flycheck-error-list-refresh)
   5350       (flycheck-error-list-recenter-at (point-min))
   5351       (force-mode-line-update))))
   5352 
   5353 (defun flycheck-error-list-apply-filter (errors)
   5354   "Filter ERRORS according to `flycheck-error-list-minimum-level'."
   5355   (if-let* ((min-level flycheck-error-list-minimum-level)
   5356             (min-severity (flycheck-error-level-severity min-level)))
   5357       (seq-filter (lambda (err) (>= (flycheck-error-level-severity
   5358                                      (flycheck-error-level err))
   5359                                     min-severity))
   5360                   errors)
   5361     errors))
   5362 
   5363 (defun flycheck-error-list-goto-error (&optional pos)
   5364   "Go to the location of the error at POS in the error list.
   5365 
   5366 POS defaults to `point'."
   5367   (interactive)
   5368   (when-let* ((error (tabulated-list-get-id pos)))
   5369     (flycheck-jump-to-error error)))
   5370 
   5371 (defun flycheck-jump-to-error (error)
   5372   "Go to the location of ERROR."
   5373   (let* ((error-copy (copy-flycheck-error error))
   5374          (filename (flycheck-error-filename error))
   5375          (other-file-error (flycheck-relevant-error-other-file-p error))
   5376          (buffer (if filename
   5377                      (find-file-noselect filename)
   5378                    (flycheck-error-buffer error))))
   5379     (when (buffer-live-p buffer)
   5380       (setf (flycheck-error-buffer error-copy) buffer)
   5381       (flycheck-jump-in-buffer buffer error-copy)
   5382       ;; When jumping to an error in another file, it may not have
   5383       ;; this error available for highlighting yet, so we trigger a check
   5384       ;; if necessary.
   5385       (when other-file-error
   5386         (with-current-buffer buffer
   5387           ;; `seq-contains-p' is only in seq >= 2.21
   5388           (unless (with-no-warnings
   5389                     (seq-contains flycheck-current-errors error-copy 'equal))
   5390             (when flycheck-mode
   5391               (flycheck-buffer))))))))
   5392 
   5393 (defun flycheck-jump-in-buffer (buffer error)
   5394   "In BUFFER, jump to ERROR."
   5395   ;; FIXME: we assume BUFFER and the buffer of ERROR are the same.  We don't
   5396   ;; need the first argument then.
   5397   (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer))
   5398       ;; When called from within the error list, keep the error list,
   5399       ;; otherwise replace the current buffer.
   5400       (pop-to-buffer buffer 'other-window)
   5401     (switch-to-buffer buffer))
   5402   (let ((pos (flycheck-error-pos error)))
   5403     (unless (eq (goto-char pos) (point))
   5404       ;; If widening gets in the way of moving to the right place, remove it
   5405       ;; and try again
   5406       (widen)
   5407       (goto-char pos)))
   5408   ;; Re-highlight the errors.  We have post-command-hook for that, but calls to
   5409   ;; `flycheck-jump-in-buffer' that come from other buffers (e.g. from the error
   5410   ;; list) won't trigger it.
   5411   (flycheck-error-list-highlight-errors 'preserve-pos))
   5412 
   5413 (defun flycheck-error-list-explain-error (&optional pos)
   5414   "Explain the error at POS in the error list.
   5415 
   5416 POS defaults to `point'."
   5417   (interactive)
   5418   (when-let* ((error (tabulated-list-get-id pos))
   5419               (explainer (flycheck-checker-get (flycheck-error-checker error)
   5420                                                'error-explainer)))
   5421     (flycheck-error-with-buffer error
   5422       (when-let (explanation (funcall explainer error))
   5423         (flycheck-display-error-explanation explanation)))))
   5424 
   5425 (defun flycheck-error-list-next-error-pos (pos &optional n)
   5426   "Starting from POS get the N'th next error in the error list.
   5427 
   5428 N defaults to 1.  If N is negative, search for the previous error
   5429 instead.
   5430 
   5431 Get the beginning position of the N'th next error from POS, or
   5432 nil, if there is no next error."
   5433   (let ((n (or n 1)))
   5434     (if (>= n 0)
   5435         ;; Search forward
   5436         (while (and pos (/= n 0))
   5437           (setq n (1- n))
   5438           (setq pos (next-single-property-change pos 'tabulated-list-id)))
   5439       ;; Search backwards
   5440       (while (/= n 0)
   5441         (setq n (1+ n))
   5442         ;; We explicitly give the limit here to explicitly have the minimum
   5443         ;; point returned, to be able to move to the first error (which starts
   5444         ;; at `point-min')
   5445         (setq pos (previous-single-property-change pos 'tabulated-list-id
   5446                                                    nil (point-min)))))
   5447     pos))
   5448 
   5449 (defun flycheck-error-list-previous-error (n)
   5450   "Go to the N'th previous error in the error list."
   5451   (interactive "P")
   5452   (flycheck-error-list-next-error (- (or n 1))))
   5453 
   5454 (defun flycheck-error-list-next-error (n)
   5455   "Go to the N'th next error in the error list."
   5456   (interactive "P")
   5457   (let ((pos (flycheck-error-list-next-error-pos (point) n)))
   5458     (when (and pos (/= pos (point)))
   5459       (goto-char pos)
   5460       (save-selected-window
   5461         ;; Keep the error list selected, so that the user can navigate errors by
   5462         ;; repeatedly pressing n/p, without having to re-select the error list
   5463         ;; window.
   5464         (flycheck-error-list-goto-error)))))
   5465 
   5466 (defvar-local flycheck-error-list-highlight-overlays nil
   5467   "Error highlight overlays in the error list buffer.")
   5468 (put 'flycheck-error-list-highlight-overlays 'permanent-local t)
   5469 
   5470 (defun flycheck-error-list-highlight-errors (&optional preserve-pos)
   5471   "Highlight errors in the error list.
   5472 
   5473 Highlight all errors in the error list that are at point in the
   5474 source buffer, and on the same line as point.  Then recenter the
   5475 error list to the highlighted error, unless PRESERVE-POS is
   5476 non-nil."
   5477   (when (get-buffer flycheck-error-list-buffer)
   5478     (with-current-buffer flycheck-error-list-buffer
   5479       (let ((current-errors
   5480              (when (buffer-live-p flycheck-error-list-source-buffer)
   5481                (with-current-buffer flycheck-error-list-source-buffer
   5482                  (flycheck-overlay-errors-in (line-beginning-position)
   5483                                              (line-end-position))))))
   5484         (let ((old-overlays flycheck-error-list-highlight-overlays)
   5485               (min-point (point-max))
   5486               (max-point (point-min)))
   5487           ;; Display the new overlays first, to avoid re-display flickering
   5488           (setq flycheck-error-list-highlight-overlays nil)
   5489           (when current-errors
   5490             (let ((next-error-pos (point-min)))
   5491               (while next-error-pos
   5492                 (let* ((beg next-error-pos)
   5493                        (end (flycheck-error-list-next-error-pos beg))
   5494                        (err (tabulated-list-get-id beg)))
   5495                   (when (member err current-errors)
   5496                     (setq min-point (min min-point beg)
   5497                           max-point (max max-point beg))
   5498                     (let ((ov (make-overlay beg
   5499                                             ;; Extend overlay to the beginning
   5500                                             ;; of the next line, to highlight
   5501                                             ;; the whole line
   5502                                             (or end (point-max)))))
   5503                       (push ov flycheck-error-list-highlight-overlays)
   5504                       (setf (overlay-get ov 'flycheck-error-highlight-overlay)
   5505                             t)
   5506                       (setf (overlay-get ov 'face)
   5507                             'flycheck-error-list-highlight)))
   5508                   (setq next-error-pos end)))))
   5509           ;; Delete the old overlays
   5510           (seq-do #'delete-overlay old-overlays)
   5511           (when (and (not preserve-pos) current-errors)
   5512             ;; Move point to the middle error
   5513             (goto-char (+ min-point (/ (- max-point min-point) 2)))
   5514             (beginning-of-line)
   5515             ;; And recenter the error list at this position
   5516             (flycheck-error-list-recenter-at (point))))))))
   5517 
   5518 (defun flycheck-list-errors ()
   5519   "Show the error list for the current buffer."
   5520   (interactive)
   5521   (unless flycheck-mode
   5522     (user-error "Flycheck mode not enabled"))
   5523   ;; Create and initialize the error list
   5524   (unless (get-buffer flycheck-error-list-buffer)
   5525     (with-current-buffer (get-buffer-create flycheck-error-list-buffer)
   5526       (flycheck-error-list-mode)))
   5527   ;; Reset the error filter
   5528   (flycheck-error-list-reset-filter)
   5529   (let ((source (current-buffer)))
   5530     ;; Show the error list in a side window.  Under some configurations of
   5531     ;; `display-buffer', this may select `flycheck-error-list-buffer' (see URL
   5532     ;; `https://github.com/flycheck/flycheck/issues/1776').
   5533     (display-buffer flycheck-error-list-buffer)
   5534     ;; Adjust the source, causing a refresh
   5535     (flycheck-error-list-set-source source)))
   5536 
   5537 (defalias 'list-flycheck-errors 'flycheck-list-errors)
   5538 
   5539 
   5540 ;;; Displaying errors in the current buffer
   5541 (defun flycheck-display-errors (errors)
   5542   "Display ERRORS using `flycheck-display-errors-function'."
   5543   (when flycheck-display-errors-function
   5544     (funcall flycheck-display-errors-function errors)))
   5545 
   5546 (defvar-local flycheck-display-error-at-point-timer nil
   5547   "Timer to automatically show errors.")
   5548 
   5549 (defun flycheck-cancel-error-display-error-at-point-timer ()
   5550   "Cancel the error display timer for the current buffer."
   5551   (when flycheck-display-error-at-point-timer
   5552     (cancel-timer flycheck-display-error-at-point-timer)
   5553     (setq flycheck-display-error-at-point-timer nil)))
   5554 
   5555 (defun flycheck--error-display-tick ()
   5556   "Return point and tick counter of current buffer."
   5557   (cons (point) (buffer-modified-tick)))
   5558 
   5559 (defvar-local flycheck--last-error-display-tick nil
   5560   "Value of `flycheck--error-display-tick' when errors were last displayed.")
   5561 
   5562 (defun flycheck-display-error-at-point ()
   5563   "Display all the error messages at point."
   5564   (interactive)
   5565   ;; This function runs from a timer, so we must take care to not ignore any
   5566   ;; errors
   5567   (with-demoted-errors "Flycheck error display error: %s"
   5568     (flycheck-cancel-error-display-error-at-point-timer)
   5569     (setq flycheck--last-error-display-tick (flycheck--error-display-tick))
   5570     (when flycheck-mode
   5571       (when-let (errors (flycheck-overlay-errors-at (point)))
   5572         (flycheck-display-errors errors)))))
   5573 
   5574 (defun flycheck-display-error-at-point-soon ()
   5575   "Display error messages at point, with a delay."
   5576   (setq flycheck--last-error-display-tick nil)
   5577   (flycheck-maybe-display-error-at-point-soon))
   5578 
   5579 (defun flycheck-maybe-display-error-at-point-soon ()
   5580   "Display error message at point with a delay, unless already displayed."
   5581   (flycheck-cancel-error-display-error-at-point-timer)
   5582   (when (and (not (equal flycheck--last-error-display-tick
   5583                          (setq flycheck--last-error-display-tick
   5584                                (flycheck--error-display-tick))))
   5585              (flycheck-overlays-at (point)))
   5586     (setq flycheck-display-error-at-point-timer
   5587           (run-at-time flycheck-display-errors-delay nil
   5588                        'flycheck-display-error-at-point))))
   5589 
   5590 
   5591 ;;; Functions to display errors
   5592 (defconst flycheck-error-message-buffer "*Flycheck error messages*"
   5593   "The name of the buffer to show long error messages in.")
   5594 
   5595 (defun flycheck-error-message-buffer ()
   5596   "Get the buffer object to show long error messages in.
   5597 
   5598 Get the buffer named by variable `flycheck-error-message-buffer',
   5599 or nil if the buffer does not exist."
   5600   (get-buffer flycheck-error-message-buffer))
   5601 
   5602 (defun flycheck-may-use-echo-area-p ()
   5603   "Determine whether the echo area may be used.
   5604 
   5605 The echo area may be used if the cursor is not in the echo area,
   5606 and if the echo area is not occupied by minibuffer input."
   5607   (not (or cursor-in-echo-area (active-minibuffer-window))))
   5608 
   5609 (define-derived-mode flycheck-error-message-mode text-mode
   5610   "Flycheck error messages"
   5611   "Major mode for extended error messages.")
   5612 
   5613 (defun flycheck-display-error-messages (errors)
   5614   "Display the messages of ERRORS.
   5615 
   5616 Concatenate all non-nil messages of ERRORS as with
   5617 `flycheck-help-echo-all-error-messages', and display them with
   5618 `display-message-or-buffer', which shows the messages either in
   5619 the echo area or in a separate buffer, depending on the number of
   5620 lines.  See Info node `(elisp)Displaying Messages' for more
   5621 information.
   5622 
   5623 In the latter case, show messages in the buffer denoted by
   5624 variable `flycheck-error-message-buffer'."
   5625   (when (and errors (flycheck-may-use-echo-area-p))
   5626     (let ((message (flycheck-help-echo-all-error-messages errors)))
   5627       (display-message-or-buffer
   5628        message flycheck-error-message-buffer 'not-this-window)
   5629       ;; We cannot rely on `display-message-or-buffer' returning the right
   5630       ;; window. See URL `https://github.com/flycheck/flycheck/issues/1643'.
   5631       (when-let (buf (get-buffer flycheck-error-message-buffer))
   5632         (with-current-buffer buf
   5633           (unless (derived-mode-p 'flycheck-error-message-mode)
   5634             (flycheck-error-message-mode)))))))
   5635 
   5636 (defun flycheck-display-error-messages-unless-error-list (errors)
   5637   "Show messages of ERRORS unless the error list is visible.
   5638 
   5639 Like `flycheck-display-error-messages', but only if the error
   5640 list (see `flycheck-list-errors') is not visible in any window in
   5641 the current frame."
   5642   (unless (flycheck-get-error-list-window 'current-frame)
   5643     (flycheck-display-error-messages errors)))
   5644 
   5645 (defun flycheck-hide-error-buffer ()
   5646   "Hide the Flycheck error buffer if necessary.
   5647 
   5648 Hide the error buffer if there is no error under point."
   5649   (when-let* ((buffer (flycheck-error-message-buffer))
   5650               (window (get-buffer-window buffer)))
   5651     (unless (flycheck-overlays-at (point))
   5652       ;; save-selected-window prevents `quit-window' from changing the current
   5653       ;; buffer (see https://github.com/flycheck/flycheck/issues/648).
   5654       (save-selected-window
   5655         (quit-window nil window)))))
   5656 
   5657 
   5658 ;;; Working with errors
   5659 (defun flycheck-copy-errors-as-kill (pos &optional formatter)
   5660   "Copy each error at POS into kill ring, using FORMATTER.
   5661 
   5662 FORMATTER is a function to turn an error into a string,
   5663 defaulting to `flycheck-error-message'.
   5664 
   5665 Interactively, use `flycheck-error-format-message-and-id' as
   5666 FORMATTER with universal prefix arg, and `flycheck-error-id' with
   5667 normal prefix arg, i.e. copy the message and the ID with
   5668 universal prefix arg, and only the id with normal prefix arg."
   5669   (interactive (list (point)
   5670                      (pcase current-prefix-arg
   5671                        ((pred not) #'flycheck-error-message)
   5672                        ((pred consp) #'flycheck-error-format-message-and-id)
   5673                        (_ #'flycheck-error-id))))
   5674   (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message)
   5675                                      (flycheck-overlay-errors-at pos)))))
   5676     (when messages
   5677       (seq-do #'kill-new (reverse messages))
   5678       (message (string-join messages "\n")))))
   5679 
   5680 (defun flycheck-explain-error-at-point ()
   5681   "Display an explanation for the first explainable error at point.
   5682 
   5683 The first explainable error at point is the first error at point
   5684 with a non-nil `:error-explainer' function defined in its
   5685 checker.  The `:error-explainer' function is then called with
   5686 this error to produce the explanation to display."
   5687   (interactive)
   5688   (when-let* ((first-error
   5689                ;; Get the first error at point that has an `error-explainer'.
   5690                (seq-find (lambda (error)
   5691                            (flycheck-checker-get
   5692                             (flycheck-error-checker error) 'error-explainer))
   5693                          (flycheck-overlay-errors-at (point))))
   5694               (explainer
   5695                (flycheck-checker-get (flycheck-error-checker first-error)
   5696                                      'error-explainer))
   5697               (explanation (funcall explainer first-error)))
   5698     (flycheck-display-error-explanation explanation)))
   5699 
   5700 (defconst flycheck-explain-error-buffer "*Flycheck error explanation*"
   5701   "The name of the buffer to show error explanations.")
   5702 
   5703 (define-derived-mode flycheck-explain-error-mode help-mode
   5704   "Error explanation"
   5705   "Major mode for displaying error explanations."
   5706   (setq buffer-read-only t))
   5707 
   5708 (defun flycheck-display-error-explanation (explanation)
   5709   "Display the EXPLANATION for an error."
   5710   (pcase explanation
   5711     (`nil)
   5712     (`(url . ,url) (browse-url url))
   5713     (_ (let ((inhibit-read-only t)
   5714              (standard-output (temp-buffer-window-setup
   5715                                flycheck-explain-error-buffer)))
   5716          (with-current-buffer standard-output
   5717            (flycheck-explain-error-mode))
   5718          (cond
   5719           ((functionp explanation) (funcall explanation))
   5720           ((stringp explanation) (princ explanation))
   5721           (t (error "Unsupported error explanation: %S" explanation)))
   5722          (display-message-or-buffer standard-output nil 'not-this-window)))))
   5723 
   5724 
   5725 ;;; Syntax checkers using external commands
   5726 (defun flycheck-command-argument-p (arg)
   5727   "Check whether ARG is a valid command argument."
   5728   (pcase arg
   5729     ((pred stringp) t)
   5730     ((or `source `source-inplace `source-original) t)
   5731     (`(,(or `source `source-inplace) ,suffix)
   5732      (stringp suffix))
   5733     ((or `temporary-directory `temporary-file-name) t)
   5734     (`null-device t)
   5735     (`(config-file ,option-name ,config-file-var)
   5736      (and (stringp option-name)
   5737           (symbolp config-file-var)))
   5738     (`(config-file ,option-name ,config-file-var ,prepender)
   5739      (and (stringp option-name)
   5740           (symbolp config-file-var)
   5741           (symbolp prepender)))
   5742     (`(,(or `option `option-list) ,option-name ,option-var)
   5743      (and (stringp option-name)
   5744           (symbolp option-var)))
   5745     (`(,(or `option `option-list) ,option-name ,option-var ,prepender)
   5746      (and (stringp option-name)
   5747           (symbolp option-var)
   5748           (symbolp prepender)))
   5749     (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter)
   5750      (and (stringp option-name)
   5751           (symbolp option-var)
   5752           (symbolp prepender)
   5753           (symbolp filter)))
   5754     (`(option-flag ,option-name ,option-var)
   5755      (and (stringp option-name)
   5756           (symbolp option-var)))
   5757     (`(eval ,_) t)
   5758     (_ nil)))
   5759 
   5760 (defun flycheck-compute-working-directory (checker)
   5761   "Get the default working directory for CHECKER.
   5762 
   5763 Compute the value of `default-directory' for the invocation of
   5764 the syntax checker command, by calling the function in the
   5765 `working-directory' property of CHECKER, with CHECKER as sole
   5766 argument, and returning its value.  Signal an error if the
   5767 function returns a non-existing working directory.
   5768 
   5769 If the property is undefined or if the function returns nil
   5770 return the `default-directory' of the current buffer."
   5771   (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory))
   5772          (directory (or (and def-directory-fn
   5773                              (funcall def-directory-fn checker))
   5774                         ;; Default to the `default-directory' of the current
   5775                         ;; buffer
   5776                         default-directory)))
   5777     (unless (file-exists-p directory)
   5778       (error ":working-directory %s of syntax checker %S does not exist"
   5779              directory checker))
   5780     directory))
   5781 
   5782 ;;;###autoload
   5783 (defun flycheck-define-command-checker (symbol docstring &rest properties)
   5784   "Define SYMBOL as syntax checker to run a command.
   5785 
   5786 Define SYMBOL as generic syntax checker via
   5787 `flycheck-define-generic-checker', which uses an external command
   5788 to check the buffer.  SYMBOL and DOCSTRING are the same as for
   5789 `flycheck-define-generic-checker'.
   5790 
   5791 In addition to the properties understood by
   5792 `flycheck-define-generic-checker', the following PROPERTIES
   5793 constitute a command syntax checker.  Unless otherwise noted, all
   5794 properties are mandatory.  Note that the default `:error-filter'
   5795 of command checkers is `flycheck-sanitize-errors'.
   5796 
   5797 `:command COMMAND'
   5798      The command to run for syntax checking.
   5799 
   5800      COMMAND is a list of the form `(EXECUTABLE [ARG ...])'.
   5801 
   5802      EXECUTABLE is a string with the executable of this syntax
   5803      checker.  It can be overridden with the variable
   5804      `flycheck-SYMBOL-executable'.  Note that this variable is
   5805      NOT implicitly defined by this function.  Use
   5806      `flycheck-def-executable-var' to define this variable.
   5807 
   5808      Each ARG is an argument to the executable, either as string,
   5809      or as special symbol or form for
   5810      `flycheck-substitute-argument', which see.
   5811 
   5812 `:error-patterns PATTERNS'
   5813      A list of patterns to parse the output of the `:command'.
   5814 
   5815      Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where
   5816      LEVEL is a Flycheck error level (see
   5817      `flycheck-define-error-level'), followed by one or more RX
   5818      `SEXP's which parse an error of that level and extract line,
   5819      column, file name and the message.
   5820 
   5821      See `rx' for general information about RX, and
   5822      `flycheck-rx-to-string' for some special RX forms provided
   5823      by Flycheck.
   5824 
   5825      All patterns are applied in the order of declaration to the
   5826      whole output of the syntax checker.  Output already matched
   5827      by a pattern will not be matched by subsequent patterns.  In
   5828      other words, the first pattern wins.
   5829 
   5830      This property is optional.  If omitted, however, an
   5831      `:error-parser' is mandatory.
   5832 
   5833 `:error-parser FUNCTION'
   5834      A function to parse errors with.
   5835 
   5836      The function shall accept three arguments OUTPUT CHECKER
   5837      BUFFER.  OUTPUT is the syntax checker output as string,
   5838      CHECKER the syntax checker that was used, and BUFFER a
   5839      buffer object representing the checked buffer.  The function
   5840      must return a list of `flycheck-error' objects parsed from
   5841      OUTPUT.
   5842 
   5843      This property is optional.  If omitted, it defaults to
   5844      `flycheck-parse-with-patterns'.  In this case,
   5845      `:error-patterns' is mandatory.
   5846 
   5847 `:standard-input t'
   5848      Whether to send the buffer contents on standard input.
   5849 
   5850      If this property is given and has a non-nil value, send the
   5851      contents of the buffer on standard input.
   5852 
   5853      Defaults to nil.
   5854 
   5855 Note that you may not give `:start', `:interrupt', and
   5856 `:print-doc' for a command checker.  You can give a custom
   5857 `:verify' function, though, whose results will be appended to the
   5858 default `:verify' function of command checkers."
   5859   (declare (indent 1)
   5860            (doc-string 2))
   5861   (dolist (prop '(:start :interrupt :print-doc))
   5862     (when (plist-get properties prop)
   5863       (error "%s not allowed in definition of command syntax checker %s"
   5864              prop symbol)))
   5865 
   5866   (unless (plist-get properties :error-filter)
   5867     ;; Default to `flycheck-sanitize-errors' as error filter
   5868     (setq properties (plist-put properties :error-filter
   5869                                 #'flycheck-sanitize-errors)))
   5870   (let ((verify-fn (plist-get properties :verify)))
   5871     (setq properties
   5872           (plist-put properties :verify
   5873                      (lambda (checker)
   5874                        (append (flycheck-verify-command-checker checker)
   5875                                (and verify-fn
   5876                                     (funcall verify-fn checker)))))))
   5877 
   5878   (let ((command (plist-get properties :command))
   5879         (patterns (plist-get properties :error-patterns))
   5880         (parser (or (plist-get properties :error-parser)
   5881                     #'flycheck-parse-with-patterns))
   5882         (enabled (plist-get properties :enabled))
   5883         (standard-input (plist-get properties :standard-input)))
   5884     (unless command
   5885       (error "Missing :command in syntax checker %s" symbol))
   5886     (unless (stringp (car command))
   5887       (error "Command executable for syntax checker %s must be a string: %S"
   5888              symbol (car command)))
   5889     (dolist (arg (cdr command))
   5890       (unless (flycheck-command-argument-p arg)
   5891         (error "Invalid command argument %S in syntax checker %s" arg symbol)))
   5892     (when (and (eq parser 'flycheck-parse-with-patterns)
   5893                (not patterns))
   5894       (error "Missing :error-patterns in syntax checker %s" symbol))
   5895 
   5896     (setq properties
   5897           ;; Automatically disable command checkers if the executable does not
   5898           ;; exist.
   5899           (plist-put properties :enabled
   5900                      (lambda ()
   5901                        (and (flycheck-find-checker-executable symbol)
   5902                             (flycheck-temp-files-writable-p symbol)
   5903                             (or (not enabled) (funcall enabled))))))
   5904 
   5905     (apply #'flycheck-define-generic-checker symbol docstring
   5906            :start #'flycheck-start-command-checker
   5907            :interrupt #'flycheck-interrupt-command-checker
   5908            :print-doc #'flycheck-command-checker-print-doc
   5909            properties)
   5910 
   5911     ;; Pre-compile all errors patterns into strings, so that we don't need to do
   5912     ;; that on each error parse
   5913     (let ((patterns (seq-map (lambda (p)
   5914                                (cons (flycheck-rx-to-string `(and ,@(cdr p))
   5915                                                             'no-group)
   5916                                      (car p)))
   5917                              patterns)))
   5918       (pcase-dolist (`(,prop . ,value)
   5919                      `((command        . ,command)
   5920                        (error-parser   . ,parser)
   5921                        (error-patterns . ,patterns)
   5922                        (standard-input . ,standard-input)))
   5923         (setf (flycheck-checker-get symbol prop) value)))))
   5924 
   5925 (eval-and-compile
   5926   ;; Make this function available during byte-compilation, since we need it
   5927   ;; at macro expansion of `flycheck-def-executable-var'.
   5928   (defun flycheck-checker-executable-variable (checker)
   5929     "Get the executable variable of CHECKER.
   5930 
   5931 The executable variable is named `flycheck-CHECKER-executable'."
   5932     (intern (format "flycheck-%s-executable" checker))))
   5933 
   5934 (defun flycheck-checker-default-executable (checker)
   5935   "Get the default executable of CHECKER."
   5936   (car (flycheck-checker-get checker 'command)))
   5937 
   5938 (defun flycheck-checker-executable (checker)
   5939   "Get the command executable of CHECKER.
   5940 
   5941 The executable is either the value of the variable
   5942 `flycheck-CHECKER-executable', or the default executable given in
   5943 the syntax checker definition, if the variable is nil."
   5944   (let ((var (flycheck-checker-executable-variable checker)))
   5945     (or (and (boundp var) (symbol-value var))
   5946         (flycheck-checker-default-executable checker))))
   5947 
   5948 (defun flycheck-find-checker-executable (checker)
   5949   "Get the full path of the executable of CHECKER.
   5950 
   5951 Return the full absolute path to the executable of CHECKER, or
   5952 nil if the executable does not exist."
   5953   (funcall flycheck-executable-find (flycheck-checker-executable checker)))
   5954 
   5955 (defun flycheck-call-checker-process
   5956     (checker infile destination error &rest args)
   5957   "Call CHECKER's executable with ARGS.
   5958 
   5959 Return nil (or raise an error if ERROR is non-nil) when CHECKER's
   5960 executable cannot be found, and return a numeric exit status or a
   5961 signal description string otherwise.  CHECKER's input is taken
   5962 from INFILE, and its output is sent to DESTINATION, as in
   5963 `call-process'."
   5964   (if-let (executable (flycheck-find-checker-executable checker))
   5965       (condition-case err
   5966           (apply #'call-process executable infile destination nil args)
   5967         (error (when error (signal (car err) (cdr err)))))
   5968     (when error
   5969       (user-error "Cannot find `%s' using `flycheck-executable-find'"
   5970                   (flycheck-checker-executable checker)))))
   5971 
   5972 (defun flycheck-call-checker-process-for-output
   5973     (checker infile error &rest args)
   5974   "Call CHECKER's executable with ARGS and return its output.
   5975 
   5976 Call `flycheck-call-checker-process' with INFILE, ERROR, and
   5977 ARGS.  If it returns 0, return the process' output.  Otherwise,
   5978 return nil or throw an error.
   5979 
   5980 This function is similar to `flycheck-call-checker-process'
   5981 called in a `with-output-to-string' block, but it takes care of
   5982 the error checking automatically."
   5983   (let ((temp (generate-new-buffer " *temp*")))
   5984     (unwind-protect
   5985         ;; We need to call the checker process in the right buffer, so that it
   5986         ;; uses the right exec-path, checker executable, etc.  See URL
   5987         ;; `https://github.com/flycheck/flycheck/issues/1770'.
   5988         (let ((exit-code (apply #'flycheck-call-checker-process
   5989                                 checker infile temp error args))
   5990               (output (with-current-buffer temp (buffer-string))))
   5991           (if (eql 0 exit-code) output
   5992             (when error
   5993               (error "Process %s failed with %S (%s)"
   5994                      checker exit-code output))))
   5995       (kill-buffer temp))))
   5996 
   5997 (defun flycheck-checker-arguments (checker)
   5998   "Get the command arguments of CHECKER."
   5999   (cdr (flycheck-checker-get checker 'command)))
   6000 
   6001 (defun flycheck-substitute-argument (arg checker)
   6002   "Substitute ARG for CHECKER.
   6003 
   6004 Return a list of real arguments for the executable of CHECKER,
   6005 substituted for the symbolic argument ARG.  Single arguments,
   6006 e.g. if ARG is a literal strings, are wrapped in a list.
   6007 
   6008 ARG may be one of the following forms:
   6009 
   6010 STRING
   6011      Return ARG unchanged.
   6012 
   6013 `source', `source-inplace'
   6014      Create a temporary file to check and return its path.  With
   6015      `source-inplace' create the temporary file in the same
   6016      directory as the original file.  The value of
   6017      `flycheck-temp-prefix' is used as prefix of the file name.
   6018 
   6019      With `source', try to retain the non-directory component of
   6020      the buffer's file name in the temporary file.
   6021 
   6022      `source' is the preferred way to pass the input file to a
   6023      syntax checker.  `source-inplace' should only be used if the
   6024      syntax checker needs other files from the source directory,
   6025      such as include files in C.
   6026 
   6027 `(source SUFFIX)', `(source-inplace SUFFIX)'
   6028      Like `source' and `source-inplace', but ensure generated
   6029      file names end with the given suffix.  Use this when the
   6030      checker requires that file names on its command line have a
   6031      certain suffix (file extension).
   6032 
   6033 `source-original'
   6034      Return the path of the actual file to check, or an empty
   6035      string if the buffer has no file name.
   6036 
   6037      Note that the contents of the file may not be up to date
   6038      with the contents of the buffer to check.  Do not use this
   6039      as primary input to a checker, unless absolutely necessary.
   6040 
   6041      When using this symbol as primary input to the syntax
   6042      checker, add `flycheck-buffer-saved-p' to the `:predicate'.
   6043 
   6044 `temporary-directory'
   6045      Create a unique temporary directory and return its path.
   6046 
   6047 `temporary-file-name'
   6048      Return a unique temporary filename.  The file is *not*
   6049      created.
   6050 
   6051      To ignore the output of syntax checkers, try symbol
   6052      `null-device' first.
   6053 
   6054 symbol `null-device'
   6055      Return the value of variable `null-device', i.e the system
   6056      null device.
   6057 
   6058      Use this option to ignore the output of a syntax checker.
   6059      If the syntax checker cannot handle the null device, or
   6060      won't write to an existing file, try `temporary-file-name'
   6061      instead.
   6062 
   6063 `(config-file OPTION VARIABLE [PREPEND-FN])'
   6064      Search the configuration file bound to VARIABLE with
   6065      `flycheck-locate-config-file' and return a list of arguments
   6066      that pass this configuration file to the syntax checker, or
   6067      nil if the configuration file was not found.
   6068 
   6069      PREPEND-FN is called with the OPTION and the located
   6070      configuration file, and should return OPTION prepended
   6071      before the file, either a string or as list.  If omitted,
   6072      PREPEND-FN defaults to `list'.
   6073 
   6074 `(option OPTION VARIABLE [PREPEND-FN [FILTER]])'
   6075      Retrieve the value of VARIABLE and return a list of
   6076      arguments that pass this value as value for OPTION to the
   6077      syntax checker.
   6078 
   6079      PREPEND-FN is called with the OPTION and the value of
   6080      VARIABLE, and should return OPTION prepended before the
   6081      file, either a string or as list.  If omitted, PREPEND-FN
   6082      defaults to `list'.
   6083 
   6084      FILTER is an optional function to be applied to the value of
   6085      VARIABLE before prepending.  This function must return nil
   6086      or a string.  In the former case, return nil.  In the latter
   6087      case, return a list of arguments as described above.
   6088 
   6089 `(option-list OPTION VARIABLE [PREPEND-FN [FILTER]])'
   6090      Retrieve the value of VARIABLE, which must be a list,
   6091      and prepend OPTION before each item in this list, using
   6092      PREPEND-FN.
   6093 
   6094      PREPEND-FN is called with the OPTION and each item of the
   6095      list as second argument, and should return OPTION prepended
   6096      before the item, either as string or as list.  If omitted,
   6097      PREPEND-FN defaults to `list'.
   6098 
   6099      FILTER is an optional function to be applied to each item in
   6100      the list before prepending OPTION.  It shall return the
   6101      option value for each item as string, or nil, if the item is
   6102      to be ignored.
   6103 
   6104 `(option-flag OPTION VARIABLE)'
   6105      Retrieve the value of VARIABLE and return OPTION, if the
   6106      value is non-nil.  Otherwise return nil.
   6107 
   6108 `(eval FORM)'
   6109      Return the result of evaluating FORM in the buffer to be
   6110      checked.  FORM must either return a string or a list of
   6111      strings, or nil to indicate that nothing should be
   6112      substituted for CELL.  For all other return types, signal an
   6113      error
   6114 
   6115      _No_ further substitutions are performed, neither in FORM
   6116      before it is evaluated, nor in the result of evaluating
   6117      FORM.
   6118 
   6119 In all other cases, signal an error.
   6120 
   6121 Note that substitution is *not* recursive.  No symbols or cells
   6122 are substituted within the body of cells!"
   6123   (pcase arg
   6124     ((pred stringp) (list arg))
   6125     (`source
   6126      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)))
   6127     (`source-inplace
   6128      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)))
   6129     (`(source ,suffix)
   6130      (list (flycheck-save-buffer-to-temp
   6131             (lambda (filename) (flycheck-temp-file-system filename suffix)))))
   6132     (`(source-inplace ,suffix)
   6133      (list (flycheck-save-buffer-to-temp
   6134             (lambda (filename) (flycheck-temp-file-inplace filename suffix)))))
   6135     (`source-original (list (or (buffer-file-name) "")))
   6136     (`temporary-directory (list (flycheck-temp-dir-system)))
   6137     (`temporary-file-name
   6138      (let ((directory (flycheck-temp-dir-system)))
   6139        (list (make-temp-name (expand-file-name "flycheck" directory)))))
   6140     (`null-device (list null-device))
   6141     (`(config-file ,option-name ,file-name-var)
   6142      (when-let* ((value (symbol-value file-name-var))
   6143                  (file-name (flycheck-locate-config-file value checker)))
   6144        (flycheck-prepend-with-option option-name (list file-name))))
   6145     (`(config-file ,option-name ,file-name-var ,prepend-fn)
   6146      (when-let* ((value (symbol-value file-name-var))
   6147                  (file-name (flycheck-locate-config-file value checker)))
   6148        (flycheck-prepend-with-option option-name (list file-name) prepend-fn)))
   6149     (`(option ,option-name ,variable)
   6150      (when-let (value (symbol-value variable))
   6151        (unless (stringp value)
   6152          (error "Value %S of %S for option %s is not a string"
   6153                 value variable option-name))
   6154        (flycheck-prepend-with-option option-name (list value))))
   6155     (`(option ,option-name ,variable ,prepend-fn)
   6156      (when-let (value (symbol-value variable))
   6157        (unless (stringp value)
   6158          (error "Value %S of %S for option %s is not a string"
   6159                 value variable option-name))
   6160        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
   6161     (`(option ,option-name ,variable ,prepend-fn ,filter)
   6162      (when-let (value (funcall filter (symbol-value variable)))
   6163        (unless (stringp value)
   6164          (error "Value %S of %S (filter: %S) for option %s is not a string"
   6165                 value variable filter option-name))
   6166        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
   6167     (`(option-list ,option-name ,variable)
   6168      (let ((value (symbol-value variable)))
   6169        (unless (and (listp value) (seq-every-p #'stringp value))
   6170          (error "Value %S of %S for option %S is not a list of strings"
   6171                 value variable option-name))
   6172        (flycheck-prepend-with-option option-name value)))
   6173     (`(option-list ,option-name ,variable ,prepend-fn)
   6174      (let ((value (symbol-value variable)))
   6175        (unless (and (listp value) (seq-every-p #'stringp value))
   6176          (error "Value %S of %S for option %S is not a list of strings"
   6177                 value variable option-name))
   6178        (flycheck-prepend-with-option option-name value prepend-fn)))
   6179     (`(option-list ,option-name ,variable ,prepend-fn ,filter)
   6180      (let ((value (delq nil (seq-map filter (symbol-value variable)))))
   6181        (unless (and (listp value) (seq-every-p #'stringp value))
   6182          (error "Value %S of %S for option %S is not a list of strings"
   6183                 value variable option-name))
   6184        (flycheck-prepend-with-option option-name value prepend-fn)))
   6185     (`(option-flag ,option-name ,variable)
   6186      (when (symbol-value variable)
   6187        (list option-name)))
   6188     (`(eval ,form)
   6189      (let ((result (eval form)))
   6190        (cond
   6191         ((and (listp result) (seq-every-p #'stringp result)) result)
   6192         ((stringp result) (list result))
   6193         (t (error "Invalid result from evaluation of %S: %S" form result)))))
   6194     (_ (error "Unsupported argument %S" arg))))
   6195 
   6196 (defun flycheck-checker-substituted-arguments (checker)
   6197   "Get the substituted arguments of a CHECKER.
   6198 
   6199 Substitute each argument of CHECKER using
   6200 `flycheck-substitute-argument'.  This replaces any special
   6201 symbols in the command."
   6202   (apply #'append
   6203          (seq-map (lambda (arg) (flycheck-substitute-argument arg checker))
   6204                   (flycheck-checker-arguments checker))))
   6205 
   6206 (defun flycheck--process-send-buffer-contents-chunked (process)
   6207   "Send contents of current buffer to PROCESS in small batches.
   6208 
   6209 Send the entire buffer to the standard input of PROCESS in chunks
   6210 of 4096 characters.  Chunking is done in Emacs Lisp, hence this
   6211 function is probably far less efficient than
   6212 `send-process-region'.  Use only when required."
   6213   (let ((from (point-min)))
   6214     (while (< from (point-max))
   6215       (let ((to (min (+ from 4096) (point-max))))
   6216         (process-send-region process from to)
   6217         (setq from to)))))
   6218 
   6219 (defvar flycheck-chunked-process-input
   6220   ;; Chunk process output on Windows to work around
   6221   ;; https://github.com/flycheck/flycheck/issues/794 and
   6222   ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344.  The presence of
   6223   ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1) where pipe
   6224   ;; writes on Windows are fixed.
   6225   ;;
   6226   ;; TODO: Remove option and chunking when dropping Emacs 24 support, see
   6227   ;; https://github.com/flycheck/flycheck/issues/856
   6228   (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size)))
   6229   "If non-nil send process input in small chunks.
   6230 
   6231 If this variable is non-nil `flycheck-process-send-buffer' sends
   6232 buffer contents in small chunks.
   6233 
   6234 Defaults to nil, except on Windows to work around Emacs bug
   6235 #22344.")
   6236 
   6237 (defun flycheck-process-send-buffer (process)
   6238   "Send all contents of current buffer to PROCESS.
   6239 
   6240 Sends all contents of the current buffer to the standard input of
   6241 PROCESS, and terminates standard input with EOF.
   6242 
   6243 If `flycheck-chunked-process-input' is non-nil, send buffer
   6244 contents in chunks via
   6245 `flycheck--process-send-buffer-contents-chunked', which see.
   6246 Otherwise use `process-send-region' to send all contents at once
   6247 and rely on Emacs' own buffering and chunking."
   6248   (save-restriction
   6249     (widen)
   6250     (if flycheck-chunked-process-input
   6251         (flycheck--process-send-buffer-contents-chunked process)
   6252       (process-send-region process (point-min) (point-max))))
   6253   (process-send-eof process))
   6254 
   6255 (defun flycheck--wrap-command (prog args)
   6256   "Wrap PROG and ARGS using `flycheck-command-wrapper-function'."
   6257   ;; We don't call `flycheck-executable-find' on the output of the wrapper
   6258   ;; function, since it might not expect it (an executable-find function
   6259   ;; designed to find binaries in a sandbox could get confused if we asked it
   6260   ;; about the sandboxing program itself).
   6261   (funcall flycheck-command-wrapper-function (cons prog args)))
   6262 
   6263 (defun flycheck-start-command-checker (checker callback)
   6264   "Start a command CHECKER with CALLBACK."
   6265   (let (process)
   6266     (condition-case err
   6267         (let* ((program (flycheck-find-checker-executable checker))
   6268                (args (flycheck-checker-substituted-arguments checker))
   6269                (command (flycheck--wrap-command program args))
   6270                (sentinel-events nil)
   6271                ;; Use pipes to receive output from the syntax checker.  They are
   6272                ;; more efficient and more robust than PTYs, which Emacs uses by
   6273                ;; default, and since we don't need any job control features, we
   6274                ;; can easily use pipes.
   6275                (process-connection-type nil))
   6276           ;; We pass do not associate the process with any buffer, by
   6277           ;; passing nil for the BUFFER argument of `start-process'.
   6278           ;; Instead, we just remember the buffer being checked in a
   6279           ;; process property (see below).  This neatly avoids all
   6280           ;; side-effects implied by attached a process to a buffer, which
   6281           ;; may cause conflicts with other packages.
   6282           ;;
   6283           ;; See https://github.com/flycheck/flycheck/issues/298 for an
   6284           ;; example for such a conflict.
   6285           (setq process (apply 'start-process (format "flycheck-%s" checker)
   6286                                nil command))
   6287           ;; Process sentinels can be called while sending input to the process.
   6288           ;; We want to record errors raised by process-send before calling
   6289           ;; `flycheck-handle-signal', so initially just accumulate events.
   6290           (setf (process-sentinel process)
   6291                 (lambda (_ event) (push event sentinel-events)))
   6292           (setf (process-filter process) #'flycheck-receive-checker-output)
   6293           (set-process-query-on-exit-flag process nil)
   6294           ;; Remember the syntax checker, the buffer and the callback
   6295           (process-put process 'flycheck-checker checker)
   6296           (process-put process 'flycheck-callback callback)
   6297           (process-put process 'flycheck-buffer (current-buffer))
   6298           ;; The default directory is bound in the `flycheck-syntax-check-start'
   6299           ;; function.
   6300           (process-put process 'flycheck-working-directory default-directory)
   6301           ;; Track the temporaries created by argument substitution in the
   6302           ;; process itself, to get rid of the global state ASAP.
   6303           (process-put process 'flycheck-temporaries flycheck-temporaries)
   6304           (setq flycheck-temporaries nil)
   6305           ;; Send the buffer to the process on standard input, if enabled.
   6306           (when (flycheck-checker-get checker 'standard-input)
   6307             (condition-case err
   6308                 (flycheck-process-send-buffer process)
   6309               ;; Some checkers exit before reading all input, causing errors
   6310               ;; such as a `file-error' for a closed pipe, or a plain “no longer
   6311               ;; connected to pipe; closed it” error for a disconnection.  We
   6312               ;; report them if needed in `flycheck-finish-checker-process' (see
   6313               ;; `https://github.com/flycheck/flycheck/issues/1278').
   6314               (error (process-put process 'flycheck-error err))))
   6315           ;; Set the actual sentinel and process any events that might have
   6316           ;; happened while we were sending input.
   6317           (setf (process-sentinel process) #'flycheck-handle-signal)
   6318           (dolist (event (nreverse sentinel-events))
   6319             (flycheck-handle-signal process event))
   6320           ;; Return the process.
   6321           process)
   6322       (error
   6323        ;; In case of error, clean up our resources, and report the error back to
   6324        ;; Flycheck.
   6325        (flycheck-safe-delete-temporaries)
   6326        (when process
   6327          ;; No need to explicitly delete the temporary files of the process,
   6328          ;; because deleting runs the sentinel, which will delete them anyway.
   6329          (delete-process process))
   6330        (signal (car err) (cdr err))))))
   6331 
   6332 (defun flycheck-interrupt-command-checker (_checker process)
   6333   "Interrupt a PROCESS."
   6334   ;; Deleting the process always triggers the sentinel, which does the cleanup
   6335   (when process
   6336     (delete-process process)))
   6337 
   6338 (defun flycheck-command-checker-print-doc (checker)
   6339   "Print additional documentation for a command CHECKER."
   6340   (let ((executable (flycheck-checker-default-executable checker))
   6341         (config-file-var (flycheck-checker-get checker 'config-file-var))
   6342         (option-vars (seq-sort #'string<
   6343                                (flycheck-checker-get checker 'option-vars))))
   6344     (princ "\n")
   6345 
   6346     (let ((doc-start (with-current-buffer standard-output (point-max))))
   6347       ;; Track the start of our documentation so that we can re-indent it
   6348       ;; properly
   6349       (princ "  This syntax checker executes \"")
   6350       (princ executable)
   6351       (princ "\"")
   6352       (when config-file-var
   6353         (princ ", using a configuration file from `")
   6354         (princ (symbol-name config-file-var))
   6355         (princ "'"))
   6356       (princ ". The executable can be overridden with `")
   6357       (princ (symbol-name (flycheck-checker-executable-variable checker)))
   6358       (princ "'.")
   6359 
   6360       (with-current-buffer standard-output
   6361         (save-excursion
   6362           (fill-region-as-paragraph doc-start (point-max)))))
   6363     (princ "\n")
   6364     (when option-vars
   6365       (princ
   6366        "\n  This syntax checker can be configured with these options:\n\n")
   6367       (dolist (var option-vars)
   6368         (princ (format "     * `%s'\n" var))))))
   6369 
   6370 (defun flycheck-verify-command-checker (checker)
   6371   "Verify a command CHECKER in the current buffer.
   6372 
   6373 Return a list of `flycheck-verification-result' objects for
   6374 CHECKER."
   6375   (let ((executable (flycheck-find-checker-executable checker))
   6376         (config-file-var (flycheck-checker-get checker 'config-file-var)))
   6377     `(
   6378       ,(flycheck-verification-result-new
   6379         :label "executable"
   6380         :message (if executable (format "Found at %s" executable) "Not found")
   6381         :face (if executable 'success '(bold error)))
   6382       ,@(when config-file-var
   6383           (let* ((value (symbol-value config-file-var))
   6384                  (path (and value (flycheck-locate-config-file value checker))))
   6385             (list (flycheck-verification-result-new
   6386                    :label "configuration file"
   6387                    :message (if path (format "Found at %S" path) "Not found")
   6388                    :face (if path 'success 'warning)))))
   6389       ,@(when (not (flycheck-temp-files-writable-p checker))
   6390           (list (flycheck-verification-result-new
   6391                  :label "temp directory"
   6392                  :message (format "%s is not writable"
   6393                                   (flycheck-temp-directory checker))
   6394                  :face 'error))))))
   6395 
   6396 
   6397 ;;; Process management for command syntax checkers
   6398 (defun flycheck-receive-checker-output (process output)
   6399   "Receive a syntax checking PROCESS OUTPUT."
   6400   (push output (process-get process 'flycheck-pending-output)))
   6401 
   6402 (defun flycheck-get-output (process)
   6403   "Get the complete output of PROCESS."
   6404   (with-demoted-errors "Error while retrieving process output: %S"
   6405     (let ((pending-output (process-get process 'flycheck-pending-output)))
   6406       (apply #'concat (nreverse pending-output)))))
   6407 
   6408 (defun flycheck-handle-signal (process _event)
   6409   "Handle a signal from the syntax checking PROCESS.
   6410 
   6411 _EVENT is ignored."
   6412   (when (memq (process-status process) '(signal exit))
   6413     (let ((files (process-get process 'flycheck-temporaries))
   6414           (buffer (process-get process 'flycheck-buffer))
   6415           (callback (process-get process 'flycheck-callback))
   6416           (cwd (process-get process 'flycheck-working-directory))
   6417           (err (process-get process 'flycheck-error)))
   6418       ;; Delete the temporary files
   6419       (seq-do #'flycheck-safe-delete files)
   6420       (when (buffer-live-p buffer)
   6421         (with-current-buffer buffer
   6422           (condition-case err
   6423               (pcase (process-status process)
   6424                 (`signal
   6425                  (funcall callback 'interrupted))
   6426                 (`exit
   6427                  (flycheck-finish-checker-process
   6428                   (process-get process 'flycheck-checker)
   6429                   (or err (process-exit-status process))
   6430                   files
   6431                   (flycheck-get-output process) callback cwd)))
   6432             ((debug error)
   6433              (funcall callback 'errored (error-message-string err)))))))))
   6434 
   6435 (defun flycheck-finish-checker-process
   6436     (checker exit-status files output callback cwd)
   6437   "Finish a checker process from CHECKER with EXIT-STATUS.
   6438 
   6439 EXIT-STATUS can be a number or an arbitrary form (if it is not 0,
   6440 a `suspicious' status is reported to CALLBACK).
   6441 
   6442 FILES is a list of files given as input to the checker.  OUTPUT
   6443 is the output of the syntax checker.  CALLBACK is the status
   6444 callback to use for reporting.
   6445 
   6446 Parse the OUTPUT and report an appropriate error status.
   6447 
   6448 Resolve all errors in OUTPUT using CWD as working directory."
   6449   (let ((errors (flycheck-parse-output output checker (current-buffer))))
   6450     (when (and (not (equal exit-status 0)) (null errors))
   6451       ;; Warn about a suspicious result from the syntax checker.  We do right
   6452       ;; after parsing the errors, before filtering, because a syntax checker
   6453       ;; might report errors from other files (e.g. includes) even if there
   6454       ;; are no errors in the file being checked.
   6455       (funcall callback 'suspicious
   6456                (format "Flycheck checker %S returned %S, but \
   6457 its output contained no errors: %s\nTry installing a more \
   6458 recent version of %S, and please open a bug report if the issue \
   6459 persists in the latest release.  Thanks!"  checker exit-status
   6460 output checker)))
   6461     (funcall callback 'finished
   6462              ;; Fix error file names, by substituting them backwards from the
   6463              ;; temporaries.
   6464              (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd))
   6465                       errors))))
   6466 
   6467 
   6468 ;;; Executables of command checkers.
   6469 (defmacro flycheck-def-executable-var (checker default-executable)
   6470   "Define the executable variable for CHECKER.
   6471 
   6472 DEFAULT-EXECUTABLE is the default executable.  It is only used in
   6473 the docstring of the variable.
   6474 
   6475 The variable is defined with `defcustom' in the
   6476 `flycheck-executables' group.  It's also defined to be risky as
   6477 file-local variable, to avoid arbitrary executables being used
   6478 for syntax checking."
   6479   (let ((executable-var (flycheck-checker-executable-variable checker)))
   6480     `(progn
   6481        (defcustom ,executable-var nil
   6482          ,(format "The executable of the %s syntax checker.
   6483 
   6484 Either a string containing the name or the path of the
   6485 executable, or nil to use the default executable from the syntax
   6486 checker declaration.
   6487 
   6488 The default executable is %S." checker default-executable)
   6489          :type '(choice (const :tag "Default executable" nil)
   6490                         (string :tag "Name or path"))
   6491          :group 'flycheck-executables
   6492          :risky t))))
   6493 
   6494 (defun flycheck-set-checker-executable (checker &optional executable)
   6495   "Set the executable of CHECKER in the current buffer.
   6496 
   6497 CHECKER is a syntax checker symbol.  EXECUTABLE is a string with
   6498 the name of an executable or the path to an executable file, which
   6499 is to be used as executable for CHECKER.  If omitted or nil,
   6500 reset the executable of CHECKER.
   6501 
   6502 Interactively, prompt for a syntax checker and an executable
   6503 file, and set the executable of the selected syntax checker.
   6504 With prefix arg, prompt for a syntax checker only, and reset the
   6505 executable of the select checker to the default.
   6506 
   6507 Set the executable variable of CHECKER, that is,
   6508 `flycheck-CHECKER-executable' to EXECUTABLE.  Signal
   6509 `user-error', if EXECUTABLE does not denote a command or an
   6510 executable file.
   6511 
   6512 This command is intended for interactive use only.  In Lisp, just
   6513 `let'-bind the corresponding variable, or set it directly.  Use
   6514 `flycheck-checker-executable-variable' to obtain the executable
   6515 variable symbol for a syntax checker."
   6516   (declare (interactive-only "Set the executable variable directly instead"))
   6517   (interactive
   6518    (let* ((checker (flycheck-read-checker "Syntax checker: "))
   6519           (default-executable (flycheck-checker-default-executable checker))
   6520           (executable (if current-prefix-arg
   6521                           nil
   6522                         (read-file-name "Executable: " nil default-executable
   6523                                         nil nil flycheck-executable-find))))
   6524      (list checker executable)))
   6525   (when (and executable (not (funcall flycheck-executable-find executable)))
   6526     (user-error "%s is no executable" executable))
   6527   (let ((variable (flycheck-checker-executable-variable checker)))
   6528     (set (make-local-variable variable) executable)))
   6529 
   6530 
   6531 ;;; Configuration files and options for command checkers
   6532 (defun flycheck-register-config-file-var (var checkers)
   6533   "Register VAR as config file var for CHECKERS.
   6534 
   6535 CHECKERS is a single syntax checker or a list thereof."
   6536   (when (symbolp checkers)
   6537     (setq checkers (list checkers)))
   6538   (dolist (checker checkers)
   6539     (setf (flycheck-checker-get checker 'config-file-var) var)))
   6540 
   6541 ;;;###autoload
   6542 (defmacro flycheck-def-config-file-var (symbol checker &optional file-name
   6543                                                &rest custom-args)
   6544   "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME.
   6545 
   6546 SYMBOL is declared as customizable variable using `defcustom', to
   6547 provide configuration files for the given syntax CHECKER.
   6548 CUSTOM-ARGS are forwarded to `defcustom'.
   6549 
   6550 FILE-NAME is the initial value of the new variable.  If omitted,
   6551 the default value is nil.  It can be either a string or a list of
   6552 strings.
   6553 
   6554 Use this together with the `config-file' form in the `:command'
   6555 argument to `flycheck-define-checker'."
   6556   (declare (indent 3))
   6557   `(progn
   6558      (defcustom ,symbol ,file-name
   6559        ,(format "Configuration file for `%s'.
   6560 
   6561 If set to a string, locate the configuration file using the
   6562 functions from `flycheck-locate-config-file-functions'.  If the
   6563 file is found pass it to the syntax checker as configuration
   6564 file.
   6565 
   6566 If no configuration file is found, or if this variable is set to
   6567 nil, invoke the syntax checker without a configuration file.
   6568 
   6569 Use this variable as file-local variable if you need a specific
   6570 configuration file for a buffer." checker)
   6571        :type '(choice (const :tag "No configuration file" nil)
   6572                       (string :tag "File name or path")
   6573                       (repeat :tag "File names or paths" string))
   6574        :safe #'flycheck-string-or-string-list-p
   6575        :group 'flycheck-config-files
   6576        ,@custom-args)
   6577      (flycheck-register-config-file-var ',symbol ',checker)))
   6578 
   6579 (defun flycheck-locate-config-file (filenames checker)
   6580   "Locate the configuration file for CHECKER, based on FILENAMES.
   6581 
   6582 FILENAMES can be either a single file, or a list.  Each filename
   6583 is passed to all `flycheck-locate-config-file-functions', until
   6584 one returns non-nil.
   6585 
   6586 Return the absolute path of the configuration file, or nil if no
   6587 configuration file was found."
   6588   (when (stringp filenames)
   6589     (setq filenames (list filenames)))
   6590   (let ((config-file nil))
   6591     (while (and filenames (null config-file))
   6592       (setq config-file (run-hook-with-args-until-success
   6593                          'flycheck-locate-config-file-functions
   6594                          (pop filenames) checker)))
   6595     (when (and config-file (file-exists-p config-file))
   6596       config-file)))
   6597 
   6598 (defun flycheck-locate-config-file-by-path (filepath _checker)
   6599   "Locate a configuration file by a FILEPATH.
   6600 
   6601 If FILEPATH is a contains a path separator, expand it against the
   6602 default directory and return it if it points to an existing file.
   6603 Otherwise return nil.
   6604 
   6605 _CHECKER is ignored."
   6606   ;; If the path is just a plain file name, skip it.
   6607   (unless (string= (file-name-nondirectory filepath) filepath)
   6608     (let ((file-name (expand-file-name filepath)))
   6609       (and (file-exists-p file-name) file-name))))
   6610 
   6611 (defun flycheck-locate-config-file-ancestor-directories (filename _checker)
   6612   "Locate a configuration FILENAME in ancestor directories.
   6613 
   6614 If the current buffer has a file name, search FILENAME in the
   6615 directory of the current buffer and all ancestors thereof (see
   6616 `locate-dominating-file').  If the file is found, return its
   6617 absolute path.  Otherwise return nil.
   6618 
   6619 _CHECKER is ignored."
   6620   (when-let* ((basefile (buffer-file-name))
   6621               (directory (locate-dominating-file basefile filename)))
   6622     (expand-file-name filename directory)))
   6623 
   6624 (defun flycheck-locate-config-file-home (filename _checker)
   6625   "Locate a configuration FILENAME in the home directory.
   6626 
   6627 Return the absolute path, if FILENAME exists in the user's home
   6628 directory, or nil otherwise."
   6629   (let ((path (expand-file-name filename "~")))
   6630     (when (file-exists-p path)
   6631       path)))
   6632 
   6633 (seq-do (apply-partially #'custom-add-frequent-value
   6634                          'flycheck-locate-config-file-functions)
   6635         '(flycheck-locate-config-file-by-path
   6636           flycheck-locate-config-file-ancestor-directories
   6637           flycheck-locate-config-file-home))
   6638 
   6639 (defun flycheck-register-option-var (var checkers)
   6640   "Register an option VAR with CHECKERS.
   6641 
   6642 VAR is an option symbol, and CHECKERS a syntax checker symbol or
   6643 a list thereof.  Register VAR with all CHECKERS so that it
   6644 appears in the help output."
   6645   (when (symbolp checkers)
   6646     (setq checkers (list checkers)))
   6647   (dolist (checker checkers)
   6648     (cl-pushnew var (flycheck-checker-get checker 'option-vars))))
   6649 
   6650 ;;;###autoload
   6651 (defmacro flycheck-def-option-var (symbol init-value checkers docstring
   6652                                           &rest custom-args)
   6653   "Define SYMBOL as option variable with INIT-VALUE for CHECKER.
   6654 
   6655 SYMBOL is declared as customizable variable using `defcustom', to
   6656 provide an option for the given syntax CHECKERS (a checker or a
   6657 list of checkers).  INIT-VALUE is the initial value of the
   6658 variable, and DOCSTRING is its docstring.  CUSTOM-ARGS are
   6659 forwarded to `defcustom'.
   6660 
   6661 Use this together with the `option', `option-list' and
   6662 `option-flag' forms in the `:command' argument to
   6663 `flycheck-define-checker'."
   6664   (declare (indent 3)
   6665            (doc-string 4))
   6666   `(progn
   6667      (defcustom ,symbol ,init-value
   6668        ,(concat docstring "
   6669 
   6670 This variable is an option for the following syntax checkers:
   6671 
   6672 "
   6673                 (mapconcat (lambda (c) (format "  - `%s'" c))
   6674                            (if (symbolp checkers) (list checkers) checkers)
   6675                            "\n"))
   6676        :group 'flycheck-options
   6677        ,@custom-args)
   6678      (flycheck-register-option-var ',symbol ',checkers)))
   6679 
   6680 (defun flycheck-option-int (value)
   6681   "Convert an integral option VALUE to a string.
   6682 
   6683 If VALUE is nil, return nil.  Otherwise return VALUE converted to
   6684 a string."
   6685   (and value (number-to-string value)))
   6686 
   6687 (defun flycheck-option-symbol (value)
   6688   "Convert a symbol option VALUE to string.
   6689 
   6690 If VALUE is nil return nil.  Otherwise return VALUE converted to
   6691 a string."
   6692   (and value (symbol-name value)))
   6693 
   6694 (defun flycheck-option-comma-separated-list (value &optional separator filter)
   6695   "Convert VALUE into a list separated by SEPARATOR.
   6696 
   6697 SEPARATOR is a string to separate items in VALUE, defaulting to
   6698 \",\".  FILTER is an optional function, which takes a single
   6699 argument and returns either a string or nil.
   6700 
   6701 If VALUE is a list, apply FILTER to each item in VALUE, remove
   6702 all nil items, and return a single string of all remaining items
   6703 separated by SEPARATOR.
   6704 
   6705 Otherwise, apply FILTER to VALUE and return the result.
   6706 SEPARATOR is ignored in this case."
   6707   (let ((filter (or filter #'identity))
   6708         (separator (or separator ",")))
   6709     (if (listp value)
   6710         (when-let (value (delq nil (seq-map filter value)))
   6711           (string-join value separator))
   6712       (funcall filter value))))
   6713 
   6714 (defmacro flycheck-def-args-var (symbol checkers &rest custom-args)
   6715   "Define SYMBOL as argument variable for CHECKERS.
   6716 
   6717 SYMBOL is declared as customizable, risky and buffer-local
   6718 variable using `defcustom' to provide an option for arbitrary
   6719 arguments for the given syntax CHECKERS (either a single checker
   6720 or a list of checkers).  CUSTOM-ARGS is forwarded to `defcustom'.
   6721 
   6722 Use the `eval' form to splice this variable into the
   6723 `:command'."
   6724   (declare (indent 2))
   6725   `(flycheck-def-option-var ,symbol nil ,checkers
   6726      "A list of additional command line arguments.
   6727 
   6728 The value of this variable is a list of strings with additional
   6729 command line arguments."
   6730      :risky t
   6731      :type '(repeat (string :tag "Argument"))
   6732      ,@custom-args))
   6733 
   6734 
   6735 ;;; Command syntax checkers as compile commands
   6736 (defun flycheck-checker-pattern-to-error-regexp (pattern)
   6737   "Convert PATTERN into an error regexp for compile.el.
   6738 
   6739 Return a list representing PATTERN, suitable as element in
   6740 `compilation-error-regexp-alist'."
   6741   (let* ((regexp (car pattern))
   6742          (level (cdr pattern))
   6743          (level-no (flycheck-error-level-compilation-level level)))
   6744     `(,regexp 1 (2 . 6) (3 . 7) ,level-no)))
   6745 
   6746 (defun flycheck-checker-compilation-error-regexp-alist (checker)
   6747   "Convert error patterns of CHECKER for use with compile.el.
   6748 
   6749 Return an alist of all error patterns of CHECKER, suitable for
   6750 use with `compilation-error-regexp-alist'."
   6751   (seq-map #'flycheck-checker-pattern-to-error-regexp
   6752            (flycheck-checker-get checker 'error-patterns)))
   6753 
   6754 (defun flycheck--substitute-shell-command-argument (arg checker)
   6755   "Substitute ARG for CHECKER.
   6756 
   6757 Like `flycheck-substitute-argument', except for source,
   6758 source-inplace, and source-original."
   6759   (if (memq arg '(source source-inplace source-original))
   6760       (list buffer-file-name)
   6761     (flycheck-substitute-argument arg checker)))
   6762 
   6763 (defun flycheck--checker-substituted-shell-command-arguments (checker)
   6764   "Get the substituted arguments of a CHECKER to run as a shell command.
   6765 
   6766 Substitute each argument of CHECKER using
   6767 `flycheck-substitute-shell-command-argument'."
   6768   (apply #'append
   6769          (seq-map (lambda (arg)
   6770                     (flycheck--substitute-shell-command-argument arg checker))
   6771                   (flycheck-checker-arguments checker))))
   6772 
   6773 (defun flycheck-checker-shell-command (checker)
   6774   "Get a shell command for CHECKER.
   6775 
   6776 Perform substitution in the arguments of CHECKER, but with
   6777 `flycheck--substitute-shell-command-argument'.
   6778 
   6779 Return the command of CHECKER as single string, suitable for
   6780 shell execution."
   6781   ;; Note: Do NOT use `combine-and-quote-strings' here.  Despite it's name it
   6782   ;; does not properly quote shell arguments, and actually breaks for special
   6783   ;; characters.  See https://github.com/flycheck/flycheck/pull/522
   6784   (let* ((args (flycheck--checker-substituted-shell-command-arguments checker))
   6785          (program
   6786           (or (flycheck-find-checker-executable checker)
   6787               (user-error "Cannot find `%s' using `flycheck-executable-find'"
   6788                           (flycheck-checker-executable checker))))
   6789          (wrapped (flycheck--wrap-command program args))
   6790          (abs-prog
   6791           ;; The executable path returned by `flycheck-command-wrapper-function'
   6792           ;; may not be absolute, so expand it here.  See URL
   6793           ;; `https://github.com/flycheck/flycheck/issues/1461'.
   6794           (or (executable-find (car wrapped))
   6795               (user-error "Cannot find `%s' using `executable-find'"
   6796                           (car wrapped))))
   6797          (command (mapconcat #'shell-quote-argument
   6798                              (cons abs-prog (cdr wrapped)) " ")))
   6799     (if (flycheck-checker-get checker 'standard-input)
   6800         ;; If the syntax checker expects the source from standard input add an
   6801         ;; appropriate shell redirection
   6802         (concat command " < " (shell-quote-argument (buffer-file-name)))
   6803       command)))
   6804 
   6805 (defun flycheck-compile-name (_name)
   6806   "Get a name for a Flycheck compilation buffer.
   6807 
   6808 _NAME is ignored."
   6809   (format "*Flycheck %s*" (buffer-file-name)))
   6810 
   6811 (defun flycheck-compile (checker)
   6812   "Run CHECKER via `compile'.
   6813 
   6814 CHECKER must be a valid syntax checker.  Interactively, prompt
   6815 for a syntax checker to run.
   6816 
   6817 Instead of highlighting errors in the buffer, this command pops
   6818 up a separate buffer with the entire output of the syntax checker
   6819 tool, just like `compile' (\\[compile])."
   6820   (interactive
   6821    (let* ((default (flycheck-get-checker-for-buffer))
   6822           (prompt (concat
   6823                    "Run syntax checker as compile command"
   6824                    (when default (concat " [" (format "%S" default) "]"))
   6825                    ": ")))
   6826      (list (flycheck-read-checker prompt
   6827                                   (when (flycheck-checker-get default 'command)
   6828                                     default)
   6829                                   'command))))
   6830   (unless (flycheck-valid-checker-p checker)
   6831     (user-error "%S is not a valid syntax checker" checker))
   6832   (unless (buffer-file-name)
   6833     (user-error "Cannot compile a buffer without a backing file"))
   6834   (unless (flycheck-may-use-checker checker)
   6835     (user-error "Cannot use syntax checker %S in this buffer" checker))
   6836   (unless (flycheck-checker-executable checker)
   6837     (user-error "Cannot run checker %S as shell command" checker))
   6838   (save-some-buffers)
   6839   (let* ((default-directory (flycheck-compute-working-directory checker))
   6840          (command (flycheck-checker-shell-command checker))
   6841          (buffer (compilation-start command nil #'flycheck-compile-name)))
   6842     (with-current-buffer buffer
   6843       (setq-local compilation-error-regexp-alist
   6844                   (flycheck-checker-compilation-error-regexp-alist checker)))))
   6845 
   6846 
   6847 ;;; General error parsing for command checkers
   6848 (defun flycheck-parse-output (output checker buffer)
   6849   "Parse OUTPUT from CHECKER in BUFFER.
   6850 
   6851 OUTPUT is a string with the output from the checker symbol
   6852 CHECKER.  BUFFER is the buffer which was checked.
   6853 
   6854 Return the errors parsed with the error patterns of CHECKER."
   6855   (funcall (flycheck-checker-get checker 'error-parser) output checker buffer))
   6856 
   6857 (defun flycheck-fix-error-filename (err buffer-files cwd)
   6858   "Fix the file name of ERR from BUFFER-FILES.
   6859 
   6860 Resolves error file names relative to CWD directory.
   6861 
   6862 Make the file name of ERR absolute.  If the absolute file name of
   6863 ERR is in BUFFER-FILES, replace it with the value of variable
   6864 `buffer-file-name'."
   6865   (flycheck-error-with-buffer err
   6866     (when-let (filename (flycheck-error-filename err))
   6867       (when (seq-some (apply-partially #'flycheck-same-files-p
   6868                                        (expand-file-name filename cwd))
   6869                       buffer-files)
   6870         (setf (flycheck-error-filename err) buffer-file-name)
   6871         (when (and buffer-file-name (flycheck-error-message err))
   6872           (setf (flycheck-error-message err)
   6873                 (replace-regexp-in-string
   6874                  (regexp-quote filename) buffer-file-name
   6875                  (flycheck-error-message err) 'fixed-case 'literal))))))
   6876   err)
   6877 
   6878 
   6879 ;;; Error parsers for command syntax checkers
   6880 (defun flycheck-parse-xml-region (beg end)
   6881   "Parse the xml region between BEG and END.
   6882 
   6883 Wrapper around `xml-parse-region' which transforms the return
   6884 value of this function into one compatible to
   6885 `libxml-parse-xml-region' by simply returning the first element
   6886 from the node list."
   6887   (ignore-errors (car (xml-parse-region beg end))))
   6888 
   6889 (defun flycheck-parse-xml-region-with-fallback (beg end)
   6890   "Parse the xml region between BEG and END.
   6891 
   6892 Try parsing with libxml first; if that fails, revert to
   6893 `flycheck-parse-xml-region'.  Failures can be caused by incorrect
   6894 XML (see URL `https://github.com/flycheck/flycheck/issues/1298'),
   6895 or on Windows by a missing libxml DLL with a libxml-enabled Emacs
   6896 \(see URL `https://github.com/flycheck/flycheck/issues/1330')."
   6897   ;; FIXME use `libxml-available-p' when it gets implemented.
   6898   (or (and (fboundp 'libxml-parse-xml-region)
   6899            (libxml-parse-xml-region beg end))
   6900       (flycheck-parse-xml-region beg end)))
   6901 
   6902 (defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback
   6903   "Function used to parse an xml string from a region.
   6904 
   6905 The default uses libxml if available, and falls back to
   6906 `flycheck-parse-xml-region' otherwise.")
   6907 
   6908 (defun flycheck-parse-xml-string (xml)
   6909   "Parse an XML string.
   6910 
   6911 Return the document tree parsed from XML in the form `(ROOT ATTRS
   6912 BODY...)'.  ROOT is a symbol identifying the name of the root
   6913 element.  ATTRS is an alist of the attributes of the root node.
   6914 BODY is zero or more body elements, either as strings (in case of
   6915 text nodes) or as XML nodes, in the same for as the root node."
   6916   (with-temp-buffer
   6917     (insert xml)
   6918     (funcall flycheck-xml-parser (point-min) (point-max))))
   6919 
   6920 (defun flycheck-parse-checkstyle (output checker buffer)
   6921   "Parse Checkstyle errors from OUTPUT.
   6922 
   6923 Parse Checkstyle-like XML output.  Use this error parser for
   6924 checkers that have an option to output errors in this format.
   6925 
   6926 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   6927 the BUFFER that was checked respectively.
   6928 
   6929 See URL `https://checkstyle.sourceforge.net/' for information
   6930 about Checkstyle."
   6931   (pcase (flycheck-parse-xml-string output)
   6932     (`(checkstyle ,_ . ,file-nodes)
   6933      (let (errors)
   6934        (dolist (node file-nodes)
   6935          (pcase node
   6936            (`(file ,file-attrs . ,error-nodes)
   6937             (dolist (node error-nodes)
   6938               (pcase node
   6939                 (`(error ,error-attrs . ,_)
   6940                  (let-alist error-attrs
   6941                    (push (flycheck-error-new-at
   6942                           (flycheck-string-to-number-safe .line)
   6943                           (flycheck-string-to-number-safe .column)
   6944                           (pcase .severity
   6945                             (`"error"   'error)
   6946                             (`"warning" 'warning)
   6947                             (`"info"    'info)
   6948                             ;; Default to error for unknown .severity
   6949                             (_          'error))
   6950                           .message
   6951                           :checker checker :id .source
   6952                           :buffer buffer
   6953                           :filename (cdr (assq 'name file-attrs)))
   6954                          errors))))))))
   6955        (nreverse errors)))))
   6956 
   6957 (defun flycheck-parse-cppcheck (output checker buffer)
   6958   "Parse Cppcheck errors from OUTPUT.
   6959 
   6960 Parse Cppcheck XML v2 output.
   6961 
   6962 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   6963 the BUFFER that was checked respectively.
   6964 
   6965 See URL `https://cppcheck.sourceforge.net/' for more information
   6966 about Cppcheck."
   6967   (pcase (flycheck-parse-xml-string output)
   6968     (`(results ,_ . ,body)
   6969      (let (errors)
   6970        (dolist (node body)
   6971          (pcase node
   6972            (`(errors ,_ . ,error-nodes)
   6973             (dolist (node error-nodes)
   6974               (pcase node
   6975                 (`(error ,error-attrs . ,loc-nodes)
   6976                  (let ((id (cdr (assq 'id error-attrs)))
   6977                        (message (cdr (assq 'verbose error-attrs)))
   6978                        (level (pcase (cdr (assq 'severity error-attrs))
   6979                                 (`"error" 'error)
   6980                                 (`"style" 'info)
   6981                                 (`"information" 'info)
   6982                                 (_ 'warning))))
   6983                    (dolist (node loc-nodes)
   6984                      (pcase node
   6985                        (`(location ,loc-attrs . ,_)
   6986                         (let-alist loc-attrs
   6987                           (push (flycheck-error-new-at
   6988                                  (flycheck-string-to-number-safe .line)
   6989                                  nil
   6990                                  level
   6991                                  ;; cppcheck return newline characters as "\012"
   6992                                  (replace-regexp-in-string "\\\\012" "\n"
   6993                                                            message)
   6994                                  :id id
   6995                                  :checker checker
   6996                                  :buffer buffer
   6997                                  :filename .file)
   6998                                 errors))))))))))))
   6999        (nreverse errors)))))
   7000 
   7001 (defun flycheck-parse-phpmd (output checker buffer)
   7002   "Parse phpmd errors from OUTPUT.
   7003 
   7004 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7005 the BUFFER that was checked respectively.
   7006 
   7007 See URL `https://phpmd.org/' for more information about phpmd."
   7008   (pcase (flycheck-parse-xml-string output)
   7009     (`(pmd ,_ . ,body)
   7010      (let (errors)
   7011        (dolist (node body)
   7012          (pcase node
   7013            (`(file ,file-attrs . ,violation-nodes)
   7014             (let ((filename (cdr (assq 'name file-attrs))))
   7015               (dolist (node violation-nodes)
   7016                 (pcase node
   7017                   (`(violation ,vio-attrs ,(and message (pred stringp)))
   7018                    (let-alist vio-attrs
   7019                      (push
   7020                       (flycheck-error-new-at
   7021                        (flycheck-string-to-number-safe .beginline)
   7022                        nil
   7023                        'warning (string-trim message)
   7024                        ;; Ignore .endline (phpmd marks giant spans as errors)
   7025                        ;; :end-line (flycheck-string-to-number-safe .endline)
   7026                        :id .rule
   7027                        :checker checker
   7028                        :buffer buffer
   7029                        :filename filename)
   7030                       errors)))))))))
   7031        (nreverse errors)))))
   7032 
   7033 (defun flycheck-parse-reek (output checker buffer)
   7034   "Parse Reek warnings from JSON OUTPUT.
   7035 
   7036 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7037 the BUFFER that was checked respectively.
   7038 
   7039 See URL `https://github.com/troessner/reek' for more information
   7040 about Reek."
   7041   (let ((errors nil))
   7042     (dolist (message (car (flycheck-parse-json output)))
   7043       (let-alist message
   7044         (dolist (line (delete-dups .lines))
   7045           (push
   7046            (flycheck-error-new-at
   7047             line
   7048             nil
   7049             'warning (concat .context " " .message)
   7050             :id .smell_type
   7051             :checker checker
   7052             :buffer buffer
   7053             :filename .source)
   7054            errors))))
   7055     (nreverse errors)))
   7056 
   7057 (defun flycheck-parse-go-staticcheck (output checker buffer)
   7058   "Parse staticheck warnings from JSON OUTPUT.
   7059 
   7060 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7061 the BUFFER that was checked respectively.
   7062 
   7063 See URL `https://staticcheck.io/docs/formatters' for more
   7064 information about staticheck."
   7065   (let ((errors nil))
   7066     (dolist (msg (flycheck-parse-json output))
   7067       (let-alist msg
   7068         (push
   7069          (flycheck-error-new-at
   7070           .location.line
   7071           .location.column
   7072           (pcase .severity
   7073             (`"error"   'error)
   7074             (`"warning" 'warning)
   7075             (`"ignored" 'info)
   7076             ;; Default to warning for unknown .severity
   7077             (_          'warning))
   7078           .message
   7079           :id .code
   7080           :checker checker
   7081           :buffer buffer
   7082           :filename .location.file)
   7083          errors)))
   7084     (nreverse errors)))
   7085 
   7086 (defun flycheck-parse-tslint (output checker buffer)
   7087   "Parse TSLint errors from JSON OUTPUT.
   7088 
   7089 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7090 the BUFFER that was checked respectively.
   7091 
   7092 See URL `https://palantir.github.io/tslint/' for more information
   7093 about TSLint."
   7094   (seq-map (lambda (message)
   7095              (let-alist message
   7096                (flycheck-error-new-at
   7097                 (+ 1 .startPosition.line)
   7098                 (+ 1 .startPosition.character)
   7099                 (pcase .ruleSeverity
   7100                   ("ERROR"   'error)
   7101                   ("WARNING" 'warning)
   7102                   (_         'warning))
   7103                 .failure
   7104                 :id .ruleName
   7105                 :checker checker
   7106                 :buffer buffer
   7107                 :filename .name
   7108                 :end-line (+ 1 .endPosition.line)
   7109                 :end-column (+ 1 .endPosition.character))))
   7110            (car (flycheck-parse-json output))))
   7111 
   7112 (defun flycheck-parse-rust-collect-spans (span)
   7113   "Return a list of spans contained in a SPAN object."
   7114   (let ((spans))
   7115     (let-alist span
   7116       ;; With macro expansion errors, some spans will point to phony file names
   7117       ;; to indicate an error inside the std rust lib.  We skip these spans as
   7118       ;; they won't appear in flycheck anyway.
   7119       (unless (string= .file_name "<std macros>")
   7120         (push span spans))
   7121 
   7122       ;; Macro expansion errors will have a span in the 'expansion' field, so we
   7123       ;; recursively collect it.
   7124       (if .expansion.span
   7125           (append (flycheck-parse-rust-collect-spans .expansion.span)
   7126                   spans)
   7127         spans))))
   7128 
   7129 (defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer)
   7130   "Turn a rustc DIAGNOSTIC into a `flycheck-error'.
   7131 
   7132 CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC
   7133 and the BUFFER that was checked respectively.
   7134 
   7135 DIAGNOSTIC should be a parsed JSON object describing a rustc
   7136 diagnostic, following the format described there:
   7137 
   7138 https://github.com/rust-lang/rust/blob/master/src/librustc_errors/json.rs#L154"
   7139   (let ((error-message)
   7140         (error-level)
   7141         (error-code)
   7142         (primary-filename)
   7143         (primary-line)
   7144         (primary-column)
   7145         (primary-end-line)
   7146         (primary-end-column)
   7147         (group (make-symbol "group"))
   7148         (spans)
   7149         (children)
   7150         (errors))
   7151     ;; The diagnostic format is described in the link above.  The gist of it is
   7152     ;; that a diagnostic can have several causes in the source text; these
   7153     ;; causes are represented by spans.  The diagnostic has a message and a
   7154     ;; level (error, warning), while the spans have a filename, line, column,
   7155     ;; and an optional label.  The primary span points to the root cause of the
   7156     ;; error in the source text, while non-primary spans point to related
   7157     ;; causes.  Spans may have an 'expansion' field for macro expansion errors;
   7158     ;; these expansion fields will contain another span (and so on).  In
   7159     ;; addition, a diagnostic can also have children diagnostics that are used
   7160     ;; to provide additional information through their message field, but do not
   7161     ;; seem to contain any spans (yet).
   7162     ;;
   7163     ;; We first gather spans in order to turn every span into a flycheck error
   7164     ;; object, that we collect into the `errors' list.
   7165 
   7166     ;; Nested `let-alist' cause compilation warnings, hence we `setq' all
   7167     ;; these values here first to avoid nesting.
   7168     (let-alist diagnostic
   7169       (setq error-message .message
   7170             error-level (pcase .level
   7171                           (`"error" 'error)
   7172                           (`"warning" 'warning)
   7173                           (`"note" 'info)
   7174                           (_ 'error))
   7175             ;; The 'code' field of the diagnostic contains the actual error
   7176             ;; code and an optional explanation that we ignore
   7177             error-code .code.code
   7178             ;; Collect all spans recursively
   7179             spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans)
   7180             children .children))
   7181 
   7182     ;; Turn each span into a flycheck error
   7183     (dolist (span spans)
   7184       (let-alist span
   7185         ;; Children may not have filename/line/column information, so we use
   7186         ;; those from the primary span
   7187         (when .is_primary
   7188           (setq primary-filename .file_name
   7189                 primary-line .line_start
   7190                 primary-column .column_start
   7191                 primary-end-line .line_end
   7192                 primary-end-column .column_end))
   7193         (push
   7194          (flycheck-error-new-at
   7195           .line_start
   7196           .column_start
   7197           ;; Non-primary spans are used for notes
   7198           (if .is_primary error-level 'info)
   7199           (if .is_primary
   7200               ;; Primary spans may have labels with additional information
   7201               (concat error-message (when .label
   7202                                       (format " (%s)" .label)))
   7203             ;; If the label is empty, fallback on the error message,
   7204             ;; otherwise we won't be able to display anything
   7205             (or .label error-message))
   7206           :id error-code
   7207           :checker checker
   7208           :buffer buffer
   7209           :filename .file_name
   7210           :group group
   7211           :end-line .line_end
   7212           :end-column .column_end)
   7213          errors)))
   7214 
   7215     ;; Then we turn children messages into flycheck errors pointing to the
   7216     ;; location of the primary span.
   7217     (dolist (child children)
   7218       (let ((message (let-alist child .message)))
   7219         (let-alist (car (let-alist child .spans))
   7220           (push
   7221            (flycheck-error-new-at
   7222             ;; Use the line/column from the first span if there is one, or
   7223             ;; fallback to the line/column information from the primary span of
   7224             ;; the diagnostic.
   7225             (or .line_start primary-line)
   7226             (or .column_start primary-column)
   7227             'info
   7228             ;; Messages from `cargo clippy' may suggest replacement code.  In
   7229             ;; these cases, the `message' field itself is an unhelpful `try' or
   7230             ;; `change this to'.  We add the `suggested_replacement' field in
   7231             ;; these cases.
   7232             (if .suggested_replacement
   7233                 (format "%s: `%s`" message .suggested_replacement)
   7234               message)
   7235             :id error-code
   7236             :checker checker
   7237             :buffer buffer
   7238             :filename primary-filename
   7239             :group group
   7240             :end-line (or .line_end primary-end-line)
   7241             :end-column (or .column_end primary-end-column))
   7242            errors))))
   7243 
   7244     ;; If there are no spans, the error is not associated with a specific
   7245     ;; file but with the project as a whole.  We still need to report it to
   7246     ;; the user by emitting a corresponding flycheck-error object.
   7247     ;; Check whether the code is non-nil because Rust≥1.44 includes the
   7248     ;; warning count upon completion.
   7249     (when (and error-code (not spans))
   7250       (push (flycheck-error-new-at
   7251              ;; We have no specific position to attach the error to, so
   7252              ;; let's use the top of the file.
   7253              1 1
   7254              error-level
   7255              error-message
   7256              :id error-code
   7257              :checker checker
   7258              :buffer buffer
   7259              :group group)
   7260             errors))
   7261     (nreverse errors)))
   7262 
   7263 (defconst flycheck--json-parser
   7264   (if (and (functionp 'json-parse-buffer)
   7265            ;; json-parse-buffer only supports keyword arguments in Emacs 27+
   7266            (>= emacs-major-version 27))
   7267       (lambda ()
   7268         (json-parse-buffer
   7269          :object-type 'alist :array-type 'list
   7270          :null-object nil :false-object nil))
   7271     #'json-read)
   7272   "Function to use to parse JSON strings.")
   7273 
   7274 (defun flycheck-parse-json (output)
   7275   "Return parsed JSON data from OUTPUT.
   7276 
   7277 OUTPUT is a string that contains JSON data.  Each line of OUTPUT
   7278 may be either plain text, a JSON array (starting with `['), or a
   7279 JSON object (starting with `{').
   7280 
   7281 This function ignores the plain text lines, parses the JSON
   7282 lines, and returns the parsed JSON lines in a list."
   7283   (let ((objects nil)
   7284         (json-array-type 'list)
   7285         (json-false nil))
   7286     (with-temp-buffer
   7287       (insert output)
   7288       (goto-char (point-min))
   7289       (while (not (eobp))
   7290         (when (memq (char-after) '(?\{ ?\[))
   7291           (push (funcall flycheck--json-parser) objects))
   7292         (forward-line)))
   7293     (nreverse objects)))
   7294 
   7295 (defun flycheck-parse-rustc (output checker buffer)
   7296   "Parse rustc errors from OUTPUT and return a list of `flycheck-error'.
   7297 
   7298 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7299 the BUFFER that was checked respectively.
   7300 
   7301 The expected format for OUTPUT is a mix of plain text lines and
   7302 JSON lines.  This function ignores the plain text lines and
   7303 parses only JSON lines.  Each JSON line is expected to be a JSON
   7304 object that corresponds to a diagnostic from the compiler.  The
   7305 expected diagnostic format is described there:
   7306 
   7307 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
   7308   (seq-mapcat (lambda (msg)
   7309                 (flycheck-parse-rustc-diagnostic msg checker buffer))
   7310               (flycheck-parse-json output)))
   7311 
   7312 (defun flycheck-parse-cargo-rustc (output checker buffer)
   7313   "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'.
   7314 
   7315 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7316 the BUFFER that was checked respectively.
   7317 
   7318 The expected format for OUTPUT is a mix of plain text lines and
   7319 JSON lines.  This function ignores the plain text lines and
   7320 parses only JSON lines.  Each JSON line is expected to be a JSON
   7321 object that represents a message from Cargo.  The format of
   7322 messages emitted by Cargo is described in cargo's
   7323 machine_message.rs at URL `https://git.io/vh24R'."
   7324   (let ((errors))
   7325     (dolist (msg (flycheck-parse-json output))
   7326       (let-alist msg
   7327         ;; Errors and warnings from rustc are wrapped by cargo, so we filter and
   7328         ;; unwrap them, and delegate the actual construction of `flycheck-error'
   7329         ;; objects to `flycheck-parse-rustc-diagnostic'.
   7330         ;; We put the error record with nil code since flycheck regards
   7331         ;; the case of nonzero return code without any error report
   7332         ;; as abnormal result.
   7333         (when (string= .reason "compiler-message")
   7334           (push (flycheck-parse-rustc-diagnostic .message checker buffer)
   7335                 errors))))
   7336     (apply #'nconc errors)))
   7337 
   7338 ;; Some checkers output ANSI terminal colors, which don't match up
   7339 ;; with :error-patterns, so we strip those color codes from the output
   7340 ;; here before passing it along to the default behavior. This is
   7341 ;; originally only used in the rebar3 checker, but the systemd checker
   7342 ;; now also makes use of it.
   7343 ;;
   7344 ;; The relevant discussion can be found at
   7345 ;; https://github.com/flycheck/flycheck/pull/1144
   7346 (defun flycheck-parse-with-patterns-without-color (output checker buffer)
   7347   "Strip color codes from OUTPUT before passing it to the default behavior.
   7348 
   7349 CHECKER and BUFFER are passed along as well."
   7350   (flycheck-parse-with-patterns
   7351    (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
   7352    checker buffer))
   7353 
   7354 
   7355 ;;; Error parsing with regular expressions
   7356 (defun flycheck-get-regexp (patterns)
   7357   "Create a single regular expression from PATTERNS."
   7358   (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns))
   7359                 'no-group))
   7360 
   7361 (defun flycheck-tokenize-output-with-patterns (output patterns)
   7362   "Tokenize OUTPUT with PATTERNS.
   7363 
   7364 Split the output into error tokens, using all regular expressions
   7365 from the error PATTERNS.  An error token is simply a string
   7366 containing a single error from OUTPUT.  Such a token can then be
   7367 parsed into a structured error by applying the PATTERNS again,
   7368 see `flycheck-parse-error-with-patterns'.
   7369 
   7370 Return a list of error tokens."
   7371   (let ((regexp (flycheck-get-regexp patterns))
   7372         (last-match 0)
   7373         errors)
   7374     (while (string-match regexp output last-match)
   7375       (push (match-string 0 output) errors)
   7376       (setq last-match (match-end 0)))
   7377     (reverse errors)))
   7378 
   7379 (defun flycheck-try-parse-error-with-pattern (err pattern checker)
   7380   "Try to parse a single ERR with a PATTERN for CHECKER.
   7381 
   7382 Return the parsed error if PATTERN matched ERR, or nil
   7383 otherwise.
   7384 
   7385 `end-line' defaults to the value of `line' when `end-column' is
   7386 set, since checkers often omit redundant end lines (as in
   7387 <file>:<line>:<column>-<end-column>)."
   7388   (let ((regexp (car pattern))
   7389         (level (cdr pattern)))
   7390     (when (string-match regexp err)
   7391       (let ((filename (match-string 1 err))
   7392             (line (flycheck-string-to-number-safe (match-string 2 err)))
   7393             (column (flycheck-string-to-number-safe (match-string 3 err)))
   7394             (message (match-string 4 err))
   7395             (id (match-string 5 err))
   7396             (end-line (flycheck-string-to-number-safe (match-string 6 err)))
   7397             (end-column (flycheck-string-to-number-safe (match-string 7 err))))
   7398         (flycheck-error-new-at
   7399          line
   7400          column
   7401          level
   7402          (unless (string-empty-p message) message)
   7403          :id (unless (string-empty-p id) id)
   7404          :checker checker
   7405          :filename (if (or (null filename) (string-empty-p filename))
   7406                        (buffer-file-name)
   7407                      filename)
   7408          :end-line (or end-line (and end-column line))
   7409          :end-column end-column)))))
   7410 
   7411 (defun flycheck-parse-error-with-patterns (err patterns checker)
   7412   "Parse a single ERR with error PATTERNS for CHECKER.
   7413 
   7414 Apply each pattern in PATTERNS to ERR, in the given order, and
   7415 return the first parsed error."
   7416   ;; Try to parse patterns in the order of declaration to make sure that the
   7417   ;; first match wins.
   7418   (let (parsed-error)
   7419     (while (and patterns
   7420                 (not (setq parsed-error
   7421                            (flycheck-try-parse-error-with-pattern
   7422                             err (car patterns) checker))))
   7423       (setq patterns (cdr patterns)))
   7424     parsed-error))
   7425 
   7426 (defun flycheck-parse-with-patterns (output checker buffer)
   7427   "Parse OUTPUT from CHECKER with error patterns.
   7428 
   7429 Uses the error patterns of CHECKER to tokenize the output and
   7430 tries to parse each error token with all patterns, in the order
   7431 of declaration.  Hence an error is never matched twice by two
   7432 different patterns.  The pattern declared first always wins.
   7433 
   7434 _BUFFER is ignored.
   7435 
   7436 Return a list of parsed errors and warnings (as `flycheck-error'
   7437 objects)."
   7438   (with-current-buffer buffer
   7439     (let ((patterns (flycheck-checker-get checker 'error-patterns)))
   7440       (seq-map (lambda (err)
   7441                  (flycheck-parse-error-with-patterns err patterns checker))
   7442                (flycheck-tokenize-output-with-patterns output patterns)))))
   7443 
   7444 
   7445 ;;; Convenience definition of command-syntax checkers
   7446 
   7447 ;; This macro is autoloaded to prevent `with-eval-after-load' from expanding its
   7448 ;; arguments.  See https://github.com/flycheck/flycheck/issues/1398.
   7449 ;;;###autoload
   7450 (defmacro flycheck-define-checker (symbol docstring &rest properties)
   7451   "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES.
   7452 
   7453 Like `flycheck-define-command-checker', but PROPERTIES must not
   7454 be quoted.  Also, implicitly define the executable variable for
   7455 SYMBOL with `flycheck-def-executable-var'."
   7456   (declare (indent 1)
   7457            (doc-string 2))
   7458   (let ((command (plist-get properties :command))
   7459         (parser (plist-get properties :error-parser))
   7460         (filter (plist-get properties :error-filter))
   7461         (explainer (plist-get properties :error-explainer))
   7462         (predicate (plist-get properties :predicate))
   7463         (enabled-fn (plist-get properties :enabled))
   7464         (verify-fn (plist-get properties :verify)))
   7465 
   7466     `(progn
   7467        (flycheck-def-executable-var ,symbol ,(car command))
   7468 
   7469        (flycheck-define-command-checker ',symbol
   7470          ,docstring
   7471          :command ',command
   7472          ,@(when parser
   7473              `(:error-parser #',parser))
   7474          :error-patterns ',(plist-get properties :error-patterns)
   7475          ,@(when filter
   7476              `(:error-filter #',filter))
   7477          ,@(when explainer
   7478              `(:error-explainer #',explainer))
   7479          :modes ',(plist-get properties :modes)
   7480          ,@(when predicate
   7481              `(:predicate #',predicate))
   7482          :next-checkers ',(plist-get properties :next-checkers)
   7483          ,@(when enabled-fn
   7484              `(:enabled #',enabled-fn))
   7485          ,@(when verify-fn
   7486              `(:verify #',verify-fn))
   7487          :standard-input ',(plist-get properties :standard-input)
   7488          :working-directory ',(plist-get properties :working-directory)))))
   7489 
   7490 
   7491 ;;; Built-in checkers
   7492 (flycheck-def-args-var flycheck-gnat-args ada-gnat
   7493   :package-version '(flycheck . "0.20"))
   7494 
   7495 (flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat
   7496   "A list of include directories for GNAT.
   7497 
   7498 The value of this variable is a list of strings, where each
   7499 string is a directory to add to the include path of gcc.
   7500 Relative paths are relative to the file being checked."
   7501   :type '(repeat (directory :tag "Include directory"))
   7502   :safe #'flycheck-string-list-p
   7503   :package-version '(flycheck . "0.20"))
   7504 
   7505 (flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat
   7506   "The language standard to use in GNAT.
   7507 
   7508 The value of this variable is either a string denoting a language
   7509 standard, or nil, to use the default standard. When non-nil, pass
   7510 the language standard via the `-std' option."
   7511   :type '(choice (const :tag "Default standard" nil)
   7512                  (string :tag "Language standard"))
   7513   :safe #'flycheck-string-or-nil-p
   7514   :package-version '(flycheck . "0.20"))
   7515 
   7516 (flycheck-def-option-var flycheck-gnat-warnings
   7517     '("wa") ada-gnat
   7518   "A list of additional Ada warnings to enable in GNAT.
   7519 
   7520 The value of this variable is a list of strings, where each
   7521 string is the name of a warning category to enable. By default,
   7522 most optional warnings are recommended, as in `-gnata'.
   7523 
   7524 Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for
   7525 more information about GNAT warnings."
   7526   :type '(repeat :tag "Warnings" (string :tag "Warning name"))
   7527   :safe #'flycheck-string-list-p
   7528   :package-version '(flycheck . "0.20"))
   7529 
   7530 (flycheck-define-checker ada-gnat
   7531   "An Ada syntax checker using GNAT.
   7532 
   7533 Uses the GNAT compiler from GCC.  See URL
   7534 `https://www.adacore.com/community/'."
   7535   :command ("gnatmake"
   7536             "-c"                        ; Just compile, don't bind
   7537             "-f"                        ; Force re-compilation
   7538             "-u"                        ; Compile the main file only
   7539             "-gnatf"                    ; Full error information
   7540             "-gnatef"                   ; Full source file name
   7541             "-D" temporary-directory
   7542             (option-list "-gnat" flycheck-gnat-warnings concat)
   7543             (option-list "-I" flycheck-gnat-include-path concat)
   7544             (option "-gnat" flycheck-gnat-language-standard concat)
   7545             (eval flycheck-gnat-args)
   7546             source)
   7547   :error-patterns
   7548   ((error line-start
   7549           (message "In file included from") " " (file-name) ":" line ":"
   7550           column ":"
   7551           line-end)
   7552    (info line-start (file-name) ":" line ":" column
   7553          ": note: " (message) line-end)
   7554    (warning line-start (file-name) ":" line ":" column
   7555             ": warning: " (message) line-end)
   7556    ;; no specific error prefix in Ada
   7557    (error line-start (file-name) ":" line ":" column
   7558           ": " (message) line-end))
   7559   :modes ada-mode)
   7560 
   7561 (flycheck-define-checker asciidoc
   7562   "A AsciiDoc syntax checker using the AsciiDoc compiler.
   7563 
   7564 See URL `https://www.methods.co.nz/asciidoc'."
   7565   :command ("asciidoc" "-o" null-device "-")
   7566   :standard-input t
   7567   :error-patterns
   7568   ((error line-start
   7569           "asciidoc: ERROR: <stdin>: Line " line ": " (message)
   7570           line-end)
   7571    (warning line-start
   7572             "asciidoc: WARNING: <stdin>: Line " line ": " (message)
   7573             line-end)
   7574    (info line-start
   7575          "asciidoc: DEPRECATED: <stdin>: Line " line ": " (message)
   7576          line-end))
   7577   :modes adoc-mode)
   7578 
   7579 (flycheck-define-checker asciidoctor
   7580   "An AsciiDoc syntax checker using the Asciidoctor compiler.
   7581 
   7582 See URL `https://asciidoctor.org'."
   7583   :command ("asciidoctor" "-o" null-device "-")
   7584   :standard-input t
   7585   :error-patterns
   7586   ((error line-start
   7587           "asciidoctor: ERROR: <stdin>: Line " line ": " (message)
   7588           line-end)
   7589    (warning line-start
   7590             "asciidoctor: WARNING: <stdin>: Line " line ": " (message)
   7591             line-end))
   7592   :modes adoc-mode)
   7593 
   7594 (defun flycheck-awk-gawk-fix-message (err)
   7595   "Remove the repeated file-name/line from the error message of ERR."
   7596   (setf (flycheck-error-message err)
   7597         (replace-regexp-in-string
   7598          (rx line-start
   7599              (group (zero-or-more (any " " "\t")))
   7600              (group (zero-or-more nonl) "\n")
   7601              (backref 1))
   7602          "\\2"
   7603          (replace-regexp-in-string
   7604           (rx "\ngawk: " (zero-or-more (not (any " "))) ":")
   7605           "\n"
   7606           (flycheck-error-message err))))
   7607   err)
   7608 
   7609 (defun flycheck-awk-gawk-error-filter (errors)
   7610   "Remove repeated file-name/line from ERRORS."
   7611   (seq-do #'flycheck-awk-gawk-fix-message errors)
   7612   errors)
   7613 
   7614 (flycheck-define-checker awk-gawk
   7615   "GNU awk's built-in --lint checker."
   7616   :command ("gawk"
   7617             ;; Avoid code execution.  See https://github.com/w0rp/ale/pull/1411
   7618             "--source" "'BEGIN{exit} END{exit 1}'"
   7619             "-f" source
   7620             "--lint"
   7621             "/dev/null")
   7622   :standard-input nil
   7623   :error-patterns
   7624   ((warning line-start
   7625             "gawk: "
   7626             (file-name) ":" line ":" (optional column ":")
   7627             (message (one-or-more not-newline)
   7628                      (optional "\n"
   7629                                (one-or-more not-newline)
   7630                                " ^ "
   7631                                (one-or-more not-newline)))
   7632             line-end))
   7633   :error-filter flycheck-awk-gawk-error-filter
   7634   :modes awk-mode)
   7635 
   7636 (flycheck-define-checker bazel-build-buildifier
   7637   "A checker for Bazel BUILD and BUILD.bazel files using buildifier.
   7638 
   7639 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7640   :command ("buildifier" "-lint=warn" "--type=build")
   7641   :standard-input t
   7642   :error-patterns
   7643   ((error line-start
   7644           "<stdin>:" line ":" column ": " (message)
   7645           line-end)
   7646    (warning line-start
   7647             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7648             line-end))
   7649   :modes bazel-build-mode)
   7650 
   7651 (flycheck-define-checker bazel-module-buildifier
   7652   "A checker for Bazel MODULE.bazel files using buildifier.
   7653 
   7654 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7655   :command ("buildifier" "-lint=warn" "--type=default")
   7656   :standard-input t
   7657   :error-patterns
   7658   ((error line-start
   7659           "<stdin>:" line ":" column ": " (message)
   7660           line-end)
   7661    (warning line-start
   7662             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7663             line-end))
   7664   :modes bazel-module-mode)
   7665 
   7666 (flycheck-define-checker bazel-starlark-buildifier
   7667   "A checker for Starlark bzl files using buildifier.
   7668 
   7669 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7670   :command ("buildifier" "-lint=warn" "--type=bzl")
   7671   :standard-input t
   7672   :error-patterns
   7673   ((error line-start
   7674           "<stdin>:" line ":" column ": " (message)
   7675           line-end)
   7676    (warning line-start
   7677             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7678             line-end))
   7679   :modes bazel-starlark-mode)
   7680 
   7681 (flycheck-define-checker bazel-workspace-buildifier
   7682   "A checker for Bazel WORKSPACE and WORKSPACE.bazel files using buildifier.
   7683 
   7684 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7685   :command ("buildifier" "-lint=warn" "--type=workspace")
   7686   :standard-input t
   7687   :error-patterns
   7688   ((error line-start
   7689           "<stdin>:" line ":" column ": " (message)
   7690           line-end)
   7691    (warning line-start
   7692             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7693             line-end))
   7694   :modes bazel-workspace-mode)
   7695 
   7696 (flycheck-def-args-var flycheck-clang-args c/c++-clang
   7697   :package-version '(flycheck . "0.22"))
   7698 
   7699 (flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang
   7700   "Enable blocks in Clang.
   7701 
   7702 When non-nil, enable blocks in Clang with `-fblocks'.  See URL
   7703 `https://clang.llvm.org/docs/BlockLanguageSpec.html' for more
   7704 information about blocks."
   7705   :type 'boolean
   7706   :safe #'booleanp
   7707   :package-version '(flycheck . "0.20"))
   7708 
   7709 (flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang
   7710   "Additional preprocessor definitions for Clang.
   7711 
   7712 The value of this variable is a list of strings, where each
   7713 string is an additional definition to pass to Clang, via the `-D'
   7714 option."
   7715   :type '(repeat (string :tag "Definition"))
   7716   :safe #'flycheck-string-list-p
   7717   :package-version '(flycheck . "0.15"))
   7718 
   7719 (flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang
   7720   "A list of include directories for Clang.
   7721 
   7722 The value of this variable is a list of strings, where each
   7723 string is a directory to add to the include path of Clang.
   7724 Relative paths are relative to the file being checked."
   7725   :type '(repeat (directory :tag "Include directory"))
   7726   :safe #'flycheck-string-list-p
   7727   :package-version '(flycheck . "0.14"))
   7728 
   7729 (flycheck-def-option-var flycheck-clang-includes nil c/c++-clang
   7730   "A list of additional include files for Clang.
   7731 
   7732 The value of this variable is a list of strings, where each
   7733 string is a file to include before syntax checking.  Relative
   7734 paths are relative to the file being checked."
   7735   :type '(repeat (file :tag "Include file"))
   7736   :safe #'flycheck-string-list-p
   7737   :package-version '(flycheck . "0.15"))
   7738 
   7739 (flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang
   7740   "The language standard to use in Clang.
   7741 
   7742 The value of this variable is either a string denoting a language
   7743 standard, or nil, to use the default standard.  When non-nil,
   7744 pass the language standard via the `-std' option."
   7745   :type '(choice (const :tag "Default standard" nil)
   7746                  (string :tag "Language standard"))
   7747   :safe #'flycheck-string-or-nil-p
   7748   :package-version '(flycheck . "0.15"))
   7749 (make-variable-buffer-local 'flycheck-clang-language-standard)
   7750 
   7751 (flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang
   7752   "Whether to enable Microsoft extensions to C/C++ in Clang.
   7753 
   7754 When non-nil, enable Microsoft extensions to C/C++ via
   7755 `-fms-extensions'."
   7756   :type 'boolean
   7757   :safe #'booleanp
   7758   :package-version '(flycheck . "0.16"))
   7759 
   7760 (flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang
   7761   "Whether to disable exceptions in Clang.
   7762 
   7763 When non-nil, disable exceptions for syntax checks, via
   7764 `-fno-exceptions'."
   7765   :type 'boolean
   7766   :safe #'booleanp
   7767   :package-version '(flycheck . "0.20"))
   7768 
   7769 (flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang
   7770   "Whether to disable RTTI in Clang.
   7771 
   7772 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
   7773   :type 'boolean
   7774   :safe #'booleanp
   7775   :package-version '(flycheck . "0.15"))
   7776 
   7777 (flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang
   7778   "Whether to warn about language extensions in Clang.
   7779 
   7780 For ISO C, follows the version specified by any -std option used.
   7781 When non-nil, disable non-ISO extensions to C/C++ via
   7782 `-pedantic'."
   7783   :type 'boolean
   7784   :safe #'booleanp
   7785   :package-version '(flycheck . "0.23"))
   7786 
   7787 (flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang
   7788   "Whether to error on language extensions in Clang.
   7789 
   7790 For ISO C, follows the version specified by any -std option used.
   7791 When non-nil, disable non-ISO extensions to C/C++ via
   7792 `-pedantic-errors'."
   7793   :type 'boolean
   7794   :safe #'booleanp
   7795   :package-version '(flycheck . "0.23"))
   7796 
   7797 (flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang
   7798   "The standard library to use for Clang.
   7799 
   7800 The value of this variable is the name of a standard library as
   7801 string, or nil to use the default standard library.
   7802 
   7803 Refer to the Clang manual at URL
   7804 `https://clang.llvm.org/docs/UsersManual.html' for more
   7805 information about the standard library."
   7806   :type '(choice (const :tag "Default standard library" nil)
   7807                  (const "libc++")
   7808                  (const :tag "GNU libstdc++" "libstdc++")
   7809                  (string :tag "Library name"))
   7810   :safe #'flycheck-string-or-nil-p
   7811   :package-version '(flycheck . "0.15"))
   7812 
   7813 (flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang
   7814   "A list of additional warnings to enable in Clang.
   7815 
   7816 The value of this variable is a list of strings, where each string
   7817 is the name of a warning category to enable.  By default, all
   7818 recommended warnings and some extra warnings are enabled (as by
   7819 `-Wall' and `-Wextra' respectively).
   7820 
   7821 Refer to the Clang manual at URL
   7822 `https://clang.llvm.org/docs/UsersManual.html' for more
   7823 information about warnings."
   7824   :type '(choice (const :tag "No additional warnings" nil)
   7825                  (repeat :tag "Additional warnings"
   7826                          (string :tag "Warning name")))
   7827   :safe #'flycheck-string-list-p
   7828   :package-version '(flycheck . "0.14"))
   7829 
   7830 (defun flycheck-c/c++-quoted-include-directory ()
   7831   "Get the directory for quoted includes.
   7832 
   7833 C/C++ compilers typically look up includes with quotation marks
   7834 in the directory of the file being compiled.  However, since
   7835 Flycheck uses temporary copies for syntax checking, it needs to
   7836 explicitly determine the directory for quoted includes.
   7837 
   7838 This function determines the directory by looking at function
   7839 `buffer-file-name', or if that is nil, at `default-directory'."
   7840   (if-let (fn (buffer-file-name))
   7841       (file-name-directory fn)
   7842     ;; If the buffer has no file name, fall back to its default directory
   7843     default-directory))
   7844 
   7845 (flycheck-define-checker c/c++-clang
   7846   "A C/C++ syntax checker using Clang.
   7847 
   7848 See URL `https://clang.llvm.org/'."
   7849   :command ("clang"
   7850             "-fsyntax-only"
   7851             "-fno-color-diagnostics"    ; Do not include color codes in output
   7852             "-fno-caret-diagnostics"    ; Do not visually indicate the source
   7853                                         ; location
   7854             "-fno-diagnostics-show-option" ; Do not show the corresponding
   7855                                         ; warning group
   7856             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   7857             (option "-std=" flycheck-clang-language-standard concat)
   7858             (option-flag "-pedantic" flycheck-clang-pedantic)
   7859             (option-flag "-pedantic-errors" flycheck-clang-pedantic-errors)
   7860             (option "-stdlib=" flycheck-clang-standard-library concat)
   7861             (option-flag "-fms-extensions" flycheck-clang-ms-extensions)
   7862             (option-flag "-fno-exceptions" flycheck-clang-no-exceptions)
   7863             (option-flag "-fno-rtti" flycheck-clang-no-rtti)
   7864             (option-flag "-fblocks" flycheck-clang-blocks)
   7865             (option-list "-include" flycheck-clang-includes)
   7866             (option-list "-W" flycheck-clang-warnings concat)
   7867             (option-list "-D" flycheck-clang-definitions concat)
   7868             (option-list "-I" flycheck-clang-include-path)
   7869             (eval flycheck-clang-args)
   7870             "-x" (eval
   7871                   (pcase major-mode
   7872                     ((or `c++-mode `c++-ts-mode) "c++")
   7873                     ((or `c-mode `c-ts-mode) "c")))
   7874             ;; Read from standard input
   7875             "-")
   7876   :standard-input t
   7877   :error-patterns
   7878   ((info line-start (or "<stdin>" (file-name)) ":" line ":" column
   7879          ": note: " (optional (message)) line-end)
   7880    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
   7881             ": warning: " (optional (message)) line-end)
   7882    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
   7883           ": " (or "fatal error" "error") ": " (optional (message)) line-end))
   7884   :error-filter
   7885   (lambda (errors)
   7886     (let ((errors (flycheck-sanitize-errors errors)))
   7887       (dolist (err errors)
   7888         ;; Clang will output empty messages for #error/#warning pragmas without
   7889         ;; messages.  We fill these empty errors with a dummy message to get
   7890         ;; them past our error filtering
   7891         (setf (flycheck-error-message err)
   7892               (or (flycheck-error-message err) "no message")))
   7893       errors))
   7894   :modes (c-mode c++-mode c-ts-mode c++-ts-mode)
   7895   :next-checkers ((warning . c/c++-cppcheck)))
   7896 
   7897 (flycheck-def-args-var flycheck-gcc-args c/c++-gcc
   7898   :package-version '(flycheck . "0.22"))
   7899 
   7900 (flycheck-def-option-var flycheck-gcc-definitions nil c/c++-gcc
   7901   "Additional preprocessor definitions for GCC.
   7902 
   7903 The value of this variable is a list of strings, where each
   7904 string is an additional definition to pass to GCC, via the `-D'
   7905 option."
   7906   :type '(repeat (string :tag "Definition"))
   7907   :safe #'flycheck-string-list-p
   7908   :package-version '(flycheck . "0.20"))
   7909 
   7910 (flycheck-def-option-var flycheck-gcc-include-path nil c/c++-gcc
   7911   "A list of include directories for GCC.
   7912 
   7913 The value of this variable is a list of strings, where each
   7914 string is a directory to add to the include path of gcc.
   7915 Relative paths are relative to the file being checked."
   7916   :type '(repeat (directory :tag "Include directory"))
   7917   :safe #'flycheck-string-list-p
   7918   :package-version '(flycheck . "0.20"))
   7919 
   7920 (flycheck-def-option-var flycheck-gcc-includes nil c/c++-gcc
   7921   "A list of additional include files for GCC.
   7922 
   7923 The value of this variable is a list of strings, where each
   7924 string is a file to include before syntax checking.  Relative
   7925 paths are relative to the file being checked."
   7926   :type '(repeat (file :tag "Include file"))
   7927   :safe #'flycheck-string-list-p
   7928   :package-version '(flycheck . "0.20"))
   7929 
   7930 (flycheck-def-option-var flycheck-gcc-language-standard nil c/c++-gcc
   7931   "The language standard to use in GCC.
   7932 
   7933 The value of this variable is either a string denoting a language
   7934 standard, or nil, to use the default standard.  When non-nil,
   7935 pass the language standard via the `-std' option."
   7936   :type '(choice (const :tag "Default standard" nil)
   7937                  (string :tag "Language standard"))
   7938   :safe #'flycheck-string-or-nil-p
   7939   :package-version '(flycheck . "0.20"))
   7940 (make-variable-buffer-local 'flycheck-gcc-language-standard)
   7941 
   7942 (flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc
   7943   "Whether to disable exceptions in GCC.
   7944 
   7945 When non-nil, disable exceptions for syntax checks, via
   7946 `-fno-exceptions'."
   7947   :type 'boolean
   7948   :safe #'booleanp
   7949   :package-version '(flycheck . "0.20"))
   7950 
   7951 (flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc
   7952   "Whether to disable RTTI in GCC.
   7953 
   7954 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
   7955   :type 'boolean
   7956   :safe #'booleanp
   7957   :package-version '(flycheck . "0.20"))
   7958 
   7959 (flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc
   7960   "Whether to enable OpenMP in GCC.
   7961 
   7962 When non-nil, enable OpenMP for syntax checkers, via
   7963 `-fopenmp'."
   7964   :type 'boolean
   7965   :safe #'booleanp
   7966   :package-version '(flycheck . "0.21"))
   7967 
   7968 (flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc
   7969   "Whether to warn about language extensions in GCC.
   7970 
   7971 For ISO C, follows the version specified by any -std option used.
   7972 When non-nil, disable non-ISO extensions to C/C++ via
   7973 `-pedantic'."
   7974   :type 'boolean
   7975   :safe #'booleanp
   7976   :package-version '(flycheck . "0.23"))
   7977 
   7978 (flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc
   7979   "Whether to error on language extensions in GCC.
   7980 
   7981 For ISO C, follows the version specified by any -std option used.
   7982 When non-nil, disable non-ISO extensions to C/C++ via
   7983 `-pedantic-errors'."
   7984   :type 'boolean
   7985   :safe #'booleanp
   7986   :package-version '(flycheck . "0.23"))
   7987 
   7988 (flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc
   7989   "A list of additional warnings to enable in GCC.
   7990 
   7991 The value of this variable is a list of strings, where each string
   7992 is the name of a warning category to enable.  By default, all
   7993 recommended warnings and some extra warnings are enabled (as by
   7994 `-Wall' and `-Wextra' respectively).
   7995 
   7996 Refer to the gcc manual at URL
   7997 `https://gcc.gnu.org/onlinedocs/gcc/' for more information about
   7998 warnings."
   7999   :type '(choice (const :tag "No additional warnings" nil)
   8000                  (repeat :tag "Additional warnings"
   8001                          (string :tag "Warning name")))
   8002   :safe #'flycheck-string-list-p
   8003   :package-version '(flycheck . "0.20"))
   8004 
   8005 (flycheck-define-checker c/c++-gcc
   8006   "A C/C++ syntax checker using GCC.
   8007 
   8008 Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
   8009   :command ("gcc"
   8010             "-fshow-column"
   8011             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   8012             (option "-std=" flycheck-gcc-language-standard concat)
   8013             (option-flag "-pedantic" flycheck-gcc-pedantic)
   8014             (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors)
   8015             (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions)
   8016             (option-flag "-fno-rtti" flycheck-gcc-no-rtti)
   8017             (option-flag "-fopenmp" flycheck-gcc-openmp)
   8018             (option-list "-include" flycheck-gcc-includes)
   8019             (option-list "-W" flycheck-gcc-warnings concat)
   8020             (option-list "-D" flycheck-gcc-definitions concat)
   8021             (option-list "-I" flycheck-gcc-include-path)
   8022             (eval flycheck-gcc-args)
   8023             "-x" (eval
   8024                   (pcase major-mode
   8025                     ((or `c++-mode `c++-ts-mode) "c++")
   8026                     ((or `c-mode `c-ts-mode) "c")))
   8027             ;; GCC performs full checking only when actually compiling, so
   8028             ;; `-fsyntax-only' is not enough. Just let it generate assembly
   8029             ;; code.
   8030             "-S" "-o" null-device
   8031             ;; Read from standard input
   8032             "-")
   8033   :standard-input t
   8034   :error-patterns
   8035   ((info line-start (or "<stdin>" (file-name))
   8036          ":" line (optional ":" column)
   8037          ": note: " (message) line-end)
   8038    (warning line-start (or "<stdin>" (file-name))
   8039             ":" line (optional ":" column)
   8040             ": warning: " (message (one-or-more (not (any "\n["))))
   8041             (optional "[" (id (one-or-more not-newline)) "]") line-end)
   8042    (error line-start (or "<stdin>" (file-name))
   8043           ":" line (optional ":" column)
   8044           ": " (or "fatal error" "error") ": " (message) line-end))
   8045   :modes (c-mode c++-mode c-ts-mode c++-ts-mode)
   8046   :next-checkers ((warning . c/c++-cppcheck)))
   8047 
   8048 (flycheck-def-option-var flycheck-cppcheck-checks '("style") c/c++-cppcheck
   8049   "Enabled checks for Cppcheck.
   8050 
   8051 The value of this variable is a list of strings, where each
   8052 string is the name of an additional check to enable.  By default,
   8053 all coding style checks are enabled.
   8054 
   8055 See section \"Enable message\" in the Cppcheck manual at URL
   8056 `https://cppcheck.sourceforge.net/manual.pdf', and the
   8057 documentation of the `--enable' option for more information,
   8058 including a list of supported checks."
   8059   :type '(repeat :tag "Additional checks"
   8060                  (string :tag "Check name"))
   8061   :safe #'flycheck-string-list-p
   8062   :package-version '(flycheck . "0.14"))
   8063 
   8064 (flycheck-def-option-var flycheck-cppcheck-standards nil c/c++-cppcheck
   8065   "The standards to use in cppcheck.
   8066 
   8067 The value of this variable is either a list of strings denoting
   8068 the standards to use, or nil to pass nothing to cppcheck.  When
   8069 non-nil, pass the standards via one or more `--std=' options."
   8070   :type '(choice (const :tag "Default" nil)
   8071                  (repeat :tag "Custom standards"
   8072                          (string :tag "Standard name")))
   8073   :safe #'flycheck-string-list-p
   8074   :package-version '(flycheck . "28"))
   8075 (make-variable-buffer-local 'flycheck-cppcheck-standards)
   8076 
   8077 (flycheck-def-option-var flycheck-cppcheck-suppressions-file nil c/c++-cppcheck
   8078   "The suppressions file to use in cppcheck.
   8079 
   8080 The value of this variable is a file with the suppressions to
   8081 use, or nil to pass nothing to cppcheck.  When non-nil, pass the
   8082 suppressions file via the `--suppressions-list=' option."
   8083   :type '(choice (const :tag "Default" nil)
   8084                  (file :tag "Suppressions file"))
   8085   :safe #'flycheck-string-or-nil-p
   8086   :package-version '(flycheck . "32"))
   8087 (make-variable-buffer-local 'flycheck-cppcheck-suppressions-file)
   8088 
   8089 (flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck
   8090   "The suppressions to use in cppcheck.
   8091 
   8092 The value of this variable is either a list of strings denoting
   8093 the suppressions to use, or nil to pass nothing to cppcheck.
   8094 When non-nil, pass the suppressions via one or more `--suppress='
   8095 options."
   8096   :type '(choice (const :tag "Default" nil)
   8097                  (repeat :tag "Additional suppressions"
   8098                          (string :tag "Suppression")))
   8099   :safe #'flycheck-string-list-p
   8100   :package-version '(flycheck . "28"))
   8101 
   8102 (flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck
   8103   "Whether to enable Cppcheck inconclusive checks.
   8104 
   8105 When non-nil, enable Cppcheck inconclusive checks.  This allows Cppcheck to
   8106 report warnings it's not certain of, but it may result in false positives.
   8107 
   8108 This will have no effect when using Cppcheck 1.53 and older."
   8109   :type 'boolean
   8110   :safe #'booleanp
   8111   :package-version '(flycheck . "0.19"))
   8112 
   8113 (flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck
   8114   "A list of include directories for cppcheck.
   8115 
   8116 The value of this variable is a list of strings, where each
   8117 string is a directory to add to the include path of cppcheck.
   8118 Relative paths are relative to the file being checked."
   8119   :type '(repeat (directory :tag "Include directory"))
   8120   :safe #'flycheck-string-list-p
   8121   :package-version '(flycheck . "0.24"))
   8122 
   8123 (flycheck-define-checker c/c++-cppcheck
   8124   "A C/C++ checker using cppcheck.
   8125 
   8126 See URL `https://cppcheck.sourceforge.net/'."
   8127   :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr"
   8128             (option "--enable=" flycheck-cppcheck-checks concat
   8129                     flycheck-option-comma-separated-list)
   8130             (option-flag "--inconclusive" flycheck-cppcheck-inconclusive)
   8131             (option-list "-I" flycheck-cppcheck-include-path)
   8132             (option-list "--std=" flycheck-cppcheck-standards concat)
   8133             (option-list "--suppress=" flycheck-cppcheck-suppressions concat)
   8134             (option "--suppressions-list="
   8135                     flycheck-cppcheck-suppressions-file concat)
   8136             "-x" (eval
   8137                   (pcase major-mode
   8138                     ((or `c++-mode `c++-ts-mode) "c++")
   8139                     ((or `c-mode `c-ts-mode) "c")))
   8140             source)
   8141   :error-parser flycheck-parse-cppcheck
   8142   :modes (c-mode c++-mode c-ts-mode c++-ts-mode))
   8143 
   8144 (flycheck-define-checker cfengine
   8145   "A CFEngine syntax checker using cf-promises.
   8146 
   8147 See URL `https://cfengine.com/'."
   8148   :command ("cf-promises" "-Wall" "-f"
   8149             ;; We must stay in the same directory to resolve @include
   8150             source-inplace)
   8151   :error-patterns
   8152   ((warning line-start (file-name) ":" line ":" column
   8153             ": warning: " (message) line-end)
   8154    (error line-start (file-name) ":" line ":" column
   8155           ": error: " (message) line-end))
   8156   :modes (cfengine-mode cfengine3-mode))
   8157 
   8158 (flycheck-define-checker coffee
   8159   "A CoffeeScript syntax checker using coffee.
   8160 
   8161 See URL `https://coffeescript.org/'."
   8162   ;; --print suppresses generation of compiled .js files
   8163   :command ("coffee" "--compile" "--print" "--stdio")
   8164   :standard-input t
   8165   :error-patterns
   8166   ((error line-start "[stdin]:" line ":" column
   8167           ": error: " (message) line-end))
   8168   :modes coffee-mode
   8169   :next-checkers ((warning . coffee-coffeelint)))
   8170 
   8171 (flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint
   8172                               ".coffeelint.json")
   8173 
   8174 (flycheck-define-checker coffee-coffeelint
   8175   "A CoffeeScript style checker using coffeelint.
   8176 
   8177 See URL `https://www.coffeelint.org/'."
   8178   :command
   8179   ("coffeelint"
   8180    (config-file "--file" flycheck-coffeelintrc)
   8181    "--stdin" "--reporter" "checkstyle")
   8182   :standard-input t
   8183   :error-parser flycheck-parse-checkstyle
   8184   :error-filter (lambda (errors)
   8185                   (flycheck-remove-error-file-names
   8186                    "stdin" (flycheck-remove-error-ids
   8187                             (flycheck-sanitize-errors errors))))
   8188   :modes coffee-mode)
   8189 
   8190 (flycheck-define-checker css-csslint
   8191   "A CSS syntax and style checker using csslint.
   8192 
   8193 See URL `https://github.com/CSSLint/csslint'."
   8194   :command ("csslint" "--format=checkstyle-xml" source)
   8195   :error-parser flycheck-parse-checkstyle
   8196   :error-filter flycheck-dequalify-error-ids
   8197   :modes (css-mode css-ts-mode))
   8198 
   8199 (defconst flycheck-stylelint-args '("--formatter" "json")
   8200   "Common arguments to stylelint invocations.")
   8201 
   8202 ;; Limit the length of the generated docstring by including only the first three
   8203 ;; checker symbols, otherwise emacs will complain about the docstring length
   8204 ;; and may refuse to compile the package.
   8205 (let ((print-length 3))
   8206   (flycheck-def-config-file-var flycheck-stylelintrc
   8207       (css-stylelint scss-stylelint sass-stylelint less-stylelint) nil))
   8208 
   8209 (flycheck-def-option-var flycheck-stylelint-quiet
   8210     nil (css-stylelint scss-stylelint sass-stylelint less-stylelint)
   8211   "Whether to run stylelint in quiet mode.
   8212 
   8213 When non-nil, enable quiet mode, via `--quiet'."
   8214   :type 'boolean
   8215   :safe #'booleanp
   8216   :package-version '(flycheck . 26))
   8217 
   8218 (defconst flycheck-stylelint-error-re
   8219   (flycheck-rx-to-string
   8220    '(: line-start (id (one-or-more word)) ": " (message) line-end)))
   8221 
   8222 (defun flycheck-parse-stylelint (output checker buffer)
   8223   "Parse stylelint errors from OUTPUT.
   8224 
   8225 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   8226 the BUFFER that was checked respectively.
   8227 
   8228 The CHECKER usually returns the errors as JSON.
   8229 
   8230 If the CHECKER throws an Error it returns an Error message with a stacktrace."
   8231   (condition-case nil
   8232       (flycheck-parse-stylelint-json output checker buffer)
   8233 
   8234     ;; The output could not be parsed as JSON
   8235     (json-error
   8236 
   8237      ;; Extract a flycheck error from the output (with a regular expression)
   8238      ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id
   8239      (when (string-match flycheck-stylelint-error-re output)
   8240        (list (flycheck-error-new-at
   8241               1 nil 'error
   8242               (match-string 4 output)
   8243               :id (match-string 5 output)
   8244               :checker checker
   8245               :buffer buffer
   8246               :filename (buffer-file-name buffer)))))))
   8247 
   8248 (defun flycheck-parse-stylelint-json (output checker buffer)
   8249   "Parse stylelint JSON errors from OUTPUT.
   8250 
   8251 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   8252 the BUFFER that was checked respectively.
   8253 
   8254 See URL `https://stylelint.io/developer-guide/formatters/' for information
   8255 about the JSON format of stylelint."
   8256   (let ((json-object-type 'plist))
   8257 
   8258     ;; stylelint returns a vector of result objects
   8259     ;; Since we only passed one file, the first element is enough
   8260     (let* ((stylelint-output (elt (json-read-from-string output) 0))
   8261            (filename (buffer-file-name buffer))
   8262 
   8263            ;; Turn all deprecations into warnings
   8264            (deprecations
   8265             (mapcar (lambda (d)
   8266                       (flycheck-error-new-at
   8267                        1 nil 'warning
   8268                        (plist-get d :text)
   8269                        :id "Deprecation Warning"
   8270                        :checker checker
   8271                        :buffer buffer
   8272                        :filename filename))
   8273                     (plist-get stylelint-output :deprecations)))
   8274 
   8275            ;; Turn all invalid options into errors
   8276            (invalid-options
   8277             (mapcar (lambda (io)
   8278                       (flycheck-error-new-at
   8279                        1 nil 'error
   8280                        (plist-get io :text)
   8281                        :id "Invalid Option"
   8282                        :checker checker
   8283                        :buffer buffer
   8284                        :filename filename))
   8285                     (plist-get stylelint-output :invalidOptionWarnings)))
   8286 
   8287            ;; Read all linting warnings
   8288            (warnings
   8289             (mapcar (lambda (w)
   8290                       (flycheck-error-new-at
   8291                        (plist-get w :line) (plist-get w :column)
   8292                        (pcase (plist-get w :severity)
   8293                          (`"error"   'error)
   8294                          (`"warning" 'warning)
   8295                          ;; Default to info for unknown .severity
   8296                          (_          'info))
   8297                        (plist-get w :text)
   8298                        :id (plist-get w :rule)
   8299                        :checker checker
   8300                        :buffer buffer
   8301                        :filename filename))
   8302                     (plist-get stylelint-output :warnings))))
   8303 
   8304       ;; Return the combined errors (deprecations, invalid options, warnings)
   8305       (append deprecations invalid-options warnings))))
   8306 
   8307 (defun flycheck--stylelint-config-exists-p (checker)
   8308   "Whether there is a valid stylelint CHECKER config for the current buffer."
   8309   (eql 0 (flycheck-call-checker-process
   8310           checker nil nil nil
   8311           "--print-config" (or buffer-file-name "index.js"))))
   8312 
   8313 (defun flycheck--stylelint-get-major-version (checker)
   8314   "Return major version of stylelint CHECKER."
   8315   (let ((cb (current-buffer)))
   8316     (with-temp-buffer
   8317       (let ((temp-buffer (current-buffer)))
   8318         (with-current-buffer cb
   8319           (flycheck-call-checker-process
   8320            checker nil temp-buffer nil "--version"))
   8321         (string-to-number (car (split-string (buffer-string) "\\.")))))))
   8322 
   8323 (defun flycheck--stylelint-verify (checker)
   8324   "Verify stylelint setup for CHECKER."
   8325   (let ((have-config (flycheck--stylelint-config-exists-p checker)))
   8326     (list
   8327      (flycheck-verification-result-new
   8328       :label "configuration available"
   8329       :message (if have-config "yes" "no config file found")
   8330       :face (if have-config 'success '(bold error)))
   8331      (flycheck-verification-result-new
   8332       :label "stylecheck version"
   8333       :message (number-to-string (flycheck--stylelint-get-major-version checker))
   8334       :face 'success))))
   8335 
   8336 (flycheck-define-checker css-stylelint
   8337   "A CSS syntax and style checker using stylelint.
   8338 
   8339 See URL `https://stylelint.io/'."
   8340   :command ("stylelint"
   8341             (eval flycheck-stylelint-args)
   8342             (option-flag "--quiet" flycheck-stylelint-quiet)
   8343             (config-file "--config" flycheck-stylelintrc)
   8344             "--stdin-filename" (eval (or (buffer-file-name) "style.css")))
   8345   :standard-input t
   8346   :verify (lambda (_) (flycheck--stylelint-verify 'css-stylelint))
   8347   :error-parser flycheck-parse-stylelint
   8348   :predicate flycheck-buffer-nonempty-p
   8349   :modes (css-mode css-ts-mode)
   8350   :error-explainer
   8351   (lambda (err)
   8352     (let ((error-code (flycheck-error-id err))
   8353           (url "https://stylelint.io/user-guide/rules/%s"))
   8354       (and error-code `(url . ,(format url error-code))))))
   8355 
   8356 (flycheck-def-option-var flycheck-cuda-language-standard nil cuda-nvcc
   8357   "Our CUDA Language Standard."
   8358   :type '(choice (const :tag "Default standard" nil)
   8359                  (string :tag "Language standard"))
   8360   :safe #'flycheck-string-or-nil-p
   8361   :package-version '(flycheck . "32"))
   8362 (make-variable-buffer-local 'flycheck-cuda-language-standard)
   8363 
   8364 (flycheck-def-option-var flycheck-cuda-gencodes nil cuda-nvcc
   8365   "Our real and virtual GPU architectures to pass to nvcc."
   8366   :type '(repeat (file :tag "GPU architecture"))
   8367   :safe #'flycheck-string-list-p
   8368   :package-version '(flycheck . "32"))
   8369 
   8370 (flycheck-def-option-var flycheck-cuda-includes nil cuda-nvcc
   8371   "Our include directories to pass to nvcc."
   8372   :type '(repeat (file :tag "Include file"))
   8373   :safe #'flycheck-string-list-p
   8374   :package-version '(flycheck . "32"))
   8375 
   8376 (flycheck-def-option-var flycheck-cuda-definitions nil cuda-nvcc
   8377   "Additional preprocessor definitions for nvcc.
   8378 A list of strings to pass to cuda, a la flycheck-clang"
   8379   :type '(repeat (string :tag "Definitions"))
   8380   :safe #'flycheck-string-list-p
   8381   :package-version '(flycheck . "32"))
   8382 
   8383 (flycheck-def-option-var flycheck-cuda-include-path nil cuda-nvcc
   8384   "A list of include directories for nvcc."
   8385   :type '(repeat (directory :tag "Include directory"))
   8386   :safe #'flycheck-string-list-p
   8387   :package-version '(flycheck . "32"))
   8388 
   8389 (flycheck-def-option-var flycheck-cuda-relaxed-constexpr nil cuda-nvcc
   8390   "Enable calling host constexpr from device function for nvcc.
   8391 
   8392 When non-nil, enable experimental calling of a constexpr __host__
   8393 function from a __device__ function."
   8394   :type 'boolean
   8395   :safe #'booleanp
   8396   :package-version '(flycheck . "35"))
   8397 
   8398 (flycheck-def-option-var flycheck-cuda-extended-lambda nil cuda-nvcc
   8399   "Enable annotating lambda functions with __host__ or __device__.
   8400 
   8401 When non-nil, enable experimental compilation of __host__ and
   8402 __device__ lambda functions."
   8403   :type 'boolean
   8404   :safe #'booleanp
   8405   :package-version '(flycheck . "35"))
   8406 
   8407 (flycheck-define-checker cuda-nvcc
   8408   "A CUDA C/C++ syntax checker using nvcc.
   8409 
   8410 See URL `https://developer.nvidia.com/cuda-llvm-compiler'."
   8411   :command ("nvcc"
   8412             "-c" ;; Compile Only
   8413             "--output-file" "/dev/null" ;; avoid creating output .o
   8414             "--x=cu" ;; explicitly specify it's a CUDA language file
   8415             "-rdc=true" ;; Allow linking with external cuda funcions
   8416             (option "-std=" flycheck-cuda-language-standard concat)
   8417             (option-flag "--expt-relaxed-constexpr" flycheck-cuda-relaxed-constexpr)
   8418             (option-flag "--expt-extended-lambda" flycheck-cuda-extended-lambda)
   8419             (option-list "-include" flycheck-cuda-includes)
   8420             (option-list "-gencode" flycheck-cuda-gencodes)
   8421             (option-list "-D" flycheck-cuda-definitions concat)
   8422             (option-list "-I" flycheck-cuda-include-path)
   8423             source)
   8424   :error-patterns
   8425   ((error line-start
   8426           (message "In file included from")
   8427           " " (or "<stdin>" (file-name))
   8428           ":" line ":" line-end)
   8429    (error line-start (or "<stdin>" (file-name))
   8430           "(" line "): error: " (message) line-end)
   8431    (error line-start (or "<stdin>" (file-name))
   8432           ":" line ":" column
   8433           ": fatal error: " (optional (message)) line-end)
   8434    (warning line-start (or "<stdin>" (file-name))
   8435             "(" line "): warning: " (message) line-end))
   8436   :modes cuda-mode)
   8437 
   8438 
   8439 (flycheck-def-option-var flycheck-cwl-schema-path nil cwl
   8440   "A path for the schema file for Common Workflow Language.
   8441 
   8442 The value of this variable is a string that denotes a path for
   8443 the schema file of Common Workflow Language."
   8444   :type '(choice (const :tag "None" nil)
   8445                  (file :tag "Schema file"))
   8446   :safe #'flycheck-string-or-nil-p)
   8447 
   8448 (flycheck-define-checker cwl
   8449   "A CWL syntax checker using Schema Salad validator.
   8450 
   8451 Requires Schema Salad 2.6.20171101113912 or newer.
   8452 See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'."
   8453   :command ("schema-salad-tool"
   8454             "--quiet"
   8455             "--print-oneline"
   8456             (eval flycheck-cwl-schema-path)
   8457             source-inplace)
   8458   :error-patterns
   8459   ((error line-start
   8460           (file-name) ":" line ":" column ":" (zero-or-more blank)
   8461           (message (one-or-more not-newline))
   8462           line-end))
   8463   :modes cwl-mode)
   8464 
   8465 (defconst flycheck-d-module-re
   8466   (rx "module" (one-or-more (syntax whitespace))
   8467       (group (one-or-more (not (syntax whitespace))))
   8468       (zero-or-more (syntax whitespace))
   8469       ";")
   8470   "Regular expression to match a D module declaration.")
   8471 
   8472 (defun flycheck-d-base-directory ()
   8473   "Get the relative base directory path for this module."
   8474   (let* ((file-name (buffer-file-name))
   8475          (module-file (if (and file-name
   8476                                (string= (file-name-nondirectory file-name)
   8477                                         "package.d"))
   8478                           (directory-file-name (file-name-directory file-name))
   8479                         file-name)))
   8480     (flycheck-module-root-directory
   8481      (flycheck-find-in-buffer flycheck-d-module-re)
   8482      module-file)))
   8483 
   8484 (flycheck-def-option-var flycheck-dmd-include-path nil d-dmd
   8485   "A list of include directories for dmd.
   8486 
   8487 The value of this variable is a list of strings, where each
   8488 string is a directory to add to the include path of dmd.
   8489 Relative paths are relative to the file being checked."
   8490   :type '(repeat (directory :tag "Include directory"))
   8491   :safe #'flycheck-string-list-p
   8492   :package-version '(flycheck . "0.18"))
   8493 
   8494 (flycheck-def-args-var flycheck-dmd-args d-dmd
   8495   :package-version '(flycheck . "0.24"))
   8496 
   8497 (flycheck-define-checker d-dmd
   8498   "A D syntax checker using the DMD compiler.
   8499 
   8500 Requires DMD 2.066 or newer.  See URL `https://dlang.org/'."
   8501   :command ("dmd"
   8502             "-debug"                    ; Compile in debug mode
   8503             "-o-"                       ; Don't generate an object file
   8504             "-vcolumns"                 ; Add columns in output
   8505             "-wi" ; Compilation will continue even if there are warnings
   8506             (eval (concat "-I" (flycheck-d-base-directory)))
   8507             (option-list "-I" flycheck-dmd-include-path concat)
   8508             (eval flycheck-dmd-args)
   8509             (source ".d"))
   8510   :error-patterns
   8511   ((error line-start
   8512           (file-name) "(" line "," column "): Error: " (message)
   8513           line-end)
   8514    (warning line-start (file-name) "(" line "," column "): "
   8515             (or "Warning" "Deprecation") ": " (message) line-end)
   8516    (info line-start (file-name) "(" line "," column "): "
   8517          (one-or-more " ") (message) line-end))
   8518   :modes d-mode)
   8519 
   8520 (flycheck-define-checker dockerfile-hadolint
   8521   "A Dockerfile syntax checker using the hadolint.
   8522 
   8523 See URL `https://github.com/hadolint/hadolint/'."
   8524   :command ("hadolint" "--no-color" "-")
   8525   :standard-input t
   8526   :error-patterns
   8527   ((error line-start
   8528           (file-name) ":" line " " (id (one-or-more alnum)) " error: " (message)
   8529           line-end)
   8530    (warning line-start
   8531             (file-name) ":" line " " (id (one-or-more alnum))
   8532             " warning: " (message) line-end)
   8533    (info line-start
   8534          (file-name) ":" line " " (id (one-or-more alnum)) " info: " (message)
   8535          line-end)
   8536    (error line-start
   8537           (file-name) ":" line ":" column " " (message)
   8538           line-end))
   8539   :error-filter
   8540   (lambda (errors)
   8541     (flycheck-sanitize-errors
   8542      (flycheck-remove-error-file-names "-" errors)))
   8543   :modes (dockerfile-mode dockerfile-ts-mode))
   8544 
   8545 (defun flycheck-credo--working-directory (&rest _ignored)
   8546   "Check if `credo' is installed as dependency in the application."
   8547   (and buffer-file-name
   8548        (locate-dominating-file buffer-file-name "deps/credo")))
   8549 
   8550 (flycheck-def-option-var flycheck-elixir-credo-strict nil elixir-credo
   8551   "Enable strict mode in `credo'.
   8552 
   8553 When non-nil, pass the `--strict' flag to credo."
   8554   :type 'boolean
   8555   :safe #'booleanp
   8556   :package-version '(flycheck . "32"))
   8557 
   8558 (flycheck-define-checker elixir-credo
   8559   "An Elixir checker for static code analysis using Credo.
   8560 
   8561 See `https://credo-ci.org/'."
   8562   :command ("mix" "credo"
   8563             (option-flag "--strict" flycheck-elixir-credo-strict)
   8564             "--format" "flycheck"
   8565             "--read-from-stdin" source-original)
   8566   :standard-input t
   8567   :working-directory flycheck-credo--working-directory
   8568   :enabled flycheck-credo--working-directory
   8569   :error-patterns
   8570   ((info line-start
   8571          (file-name) ":" line (optional ":" column) ": "
   8572          (or "F" "R" "C")  ": " (message) line-end)
   8573    (warning line-start
   8574             (file-name) ":" line (optional ":" column) ": "
   8575             (or "D" "W")  ": " (message) line-end))
   8576   :modes elixir-mode)
   8577 
   8578 (defconst flycheck-this-emacs-executable
   8579   (concat invocation-directory invocation-name)
   8580   "The path to the currently running Emacs executable.")
   8581 
   8582 (defconst flycheck-emacs-args '("-Q" "--batch")
   8583   "Common arguments to Emacs invocations.")
   8584 
   8585 (defmacro flycheck-prepare-emacs-lisp-form (&rest body)
   8586   "Prepare BODY for use as check form in a subprocess."
   8587   (declare (indent 0))
   8588   `(flycheck-sexp-to-string
   8589     '(progn
   8590        (defvar jka-compr-inhibit)
   8591        (unwind-protect
   8592            ;; Flycheck inhibits compression of temporary files, thus we
   8593            ;; must not attempt to decompress.
   8594            (let ((jka-compr-inhibit t))
   8595              ;; Strip option-argument separator from arguments, if present
   8596              (when (equal (car command-line-args-left) "--")
   8597                (setq command-line-args-left (cdr command-line-args-left)))
   8598              ,@body)
   8599          ;; Prevent Emacs from processing the arguments on its own, see
   8600          ;; https://github.com/flycheck/flycheck/issues/319
   8601          (setq command-line-args-left nil)))))
   8602 
   8603 (defun flycheck-emacs-lisp-bytecomp-config-form ()
   8604   "Prepare an Emacs Lisp form to set byte-compiler variables."
   8605   (flycheck-sexp-to-string
   8606    `(progn
   8607       (require 'bytecomp)
   8608       (setq byte-compile-root-dir
   8609             ,(if buffer-file-name
   8610                  (file-name-directory buffer-file-name)
   8611                default-directory)))))
   8612 
   8613 (defconst flycheck-emacs-lisp-check-form
   8614   (flycheck-prepare-emacs-lisp-form
   8615     ;; Keep track of the generated bytecode files, to delete them after byte
   8616     ;; compilation.
   8617     (require 'bytecomp)
   8618     (defvar flycheck-byte-compiled-files nil)
   8619     (let ((byte-compile-dest-file-function
   8620            (lambda (source)
   8621              (let ((temp-file (make-temp-file (file-name-nondirectory source))))
   8622                (push temp-file flycheck-byte-compiled-files)
   8623                temp-file))))
   8624       (unwind-protect
   8625           (byte-compile-file (car command-line-args-left))
   8626         (mapc (lambda (f) (ignore-errors (delete-file f)))
   8627               flycheck-byte-compiled-files))
   8628       (when (bound-and-true-p flycheck-emacs-lisp-check-declare)
   8629         (check-declare-file (car command-line-args-left))))))
   8630 
   8631 (flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp
   8632   "Load path to use in the Emacs Lisp syntax checker.
   8633 
   8634 When set to `inherit', use the `load-path' of the current Emacs
   8635 session during syntax checking.
   8636 
   8637 When set to a list of strings, add each directory in this list to
   8638 the `load-path' before invoking the byte compiler.  Relative
   8639 paths in this list are expanded against the `default-directory'
   8640 of the buffer to check.
   8641 
   8642 When nil, do not explicitly set the `load-path' during syntax
   8643 checking.  The syntax check only uses the built-in `load-path' of
   8644 Emacs in this case.
   8645 
   8646 Note that changing this variable can lead to wrong results of the
   8647 syntax check, e.g. if an unexpected version of a required library
   8648 is used."
   8649   :type '(choice (const :tag "Inherit current `load-path'" inherit)
   8650                  (repeat :tag "Load path" directory))
   8651   :risky t
   8652   :package-version '(flycheck . "0.14"))
   8653 
   8654 (flycheck-def-option-var flycheck-emacs-lisp-initialize-packages
   8655     'auto emacs-lisp
   8656   "Whether to initialize packages in the Emacs Lisp syntax checker.
   8657 
   8658 When nil, never initialize packages.  When `auto', initialize
   8659 packages only when checking `user-init-file' or files from
   8660 `user-emacs-directory'.  For any other non-nil value, always
   8661 initialize packages.
   8662 
   8663 When initializing packages is enabled the `emacs-lisp' syntax
   8664 checker calls `package-initialize' before byte-compiling the file
   8665 to be checked.  It also sets `package-user-dir' according to
   8666 `flycheck-emacs-lisp-package-user-dir'."
   8667   :type '(choice (const :tag "Do not initialize packages" nil)
   8668                  (const :tag "Initialize packages for configuration only" auto)
   8669                  (const :tag "Always initialize packages" t))
   8670   :risky t
   8671   :package-version '(flycheck . "0.14"))
   8672 
   8673 (defconst flycheck-emacs-lisp-package-initialize-form
   8674   (flycheck-sexp-to-string
   8675    '(with-demoted-errors "Error during package initialization: %S"
   8676       (package-initialize)))
   8677   "Form used to initialize packages.")
   8678 
   8679 (defun flycheck-option-emacs-lisp-package-initialize (value)
   8680   "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'."
   8681   (let ((shall-initialize
   8682          (if (eq value 'auto)
   8683              (or (flycheck-in-user-emacs-directory-p
   8684                   (or buffer-file-name default-directory))
   8685                  ;; `user-init-file' is nil in non-interactive sessions.  Now,
   8686                  ;; no user would possibly use Flycheck in a non-interactive
   8687                  ;; session, but our unit tests run non-interactively, so we
   8688                  ;; have to handle this case anyway
   8689                  (and user-init-file buffer-file-name
   8690                       (flycheck-same-files-p buffer-file-name user-init-file)))
   8691            value)))
   8692     (when shall-initialize
   8693       ;; If packages shall be initialized, return the corresponding form,
   8694       ;; otherwise make Flycheck ignore the option by returning nil.
   8695       flycheck-emacs-lisp-package-initialize-form)))
   8696 
   8697 (flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp
   8698   "Package directory for the Emacs Lisp syntax checker.
   8699 
   8700 If set to a string set `package-user-dir' to the value of this
   8701 variable before initializing packages. If set to nil just inherit
   8702 the value of `package-user-dir' from the running Emacs session.
   8703 
   8704 This variable has no effect, if
   8705 `flycheck-emacs-lisp-initialize-packages' is nil."
   8706   :type '(choice (const :tag "Default package directory" nil)
   8707                  (directory :tag "Custom package directory"))
   8708   :risky t
   8709   :package-version '(flycheck . "0.14"))
   8710 
   8711 (defun flycheck-option-emacs-lisp-package-user-dir (value)
   8712   "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'."
   8713   ;; Inherit the package directory from our Emacs session
   8714   (let ((value (or value (bound-and-true-p package-user-dir))))
   8715     (when value
   8716       (flycheck-sexp-to-string `(setq package-user-dir ,value)))))
   8717 
   8718 (flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp
   8719   "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’."
   8720   :type '(choice (const :tag "Do not check declare forms" nil)
   8721                  (const :tag "Check declare forms" t))
   8722   :risky t
   8723   :package-version '(flycheck . "31"))
   8724 
   8725 (defun flycheck-option-emacs-lisp-check-declare (value)
   8726   "Option VALUE filter for `flycheck-emacs-lisp-check-declare'."
   8727   (when value
   8728     (flycheck-sexp-to-string
   8729      `(progn
   8730         (defvar flycheck-emacs-lisp-check-declare)
   8731         (setq flycheck-emacs-lisp-check-declare ,value)))))
   8732 
   8733 (defun flycheck--emacs-lisp-enabled-p ()
   8734   "Check whether to enable Emacs Lisp checker in the current buffer."
   8735   (not
   8736    (or
   8737     ;; Do not check buffers used for autoloads generation during package
   8738     ;; installation.  These buffers are too short-lived for being checked, and
   8739     ;; doing so causes spurious errors.  See
   8740     ;; https://github.com/flycheck/flycheck/issues/45 and
   8741     ;; https://github.com/bbatsov/prelude/issues/248.  We must also not check
   8742     ;; compilation buffers, but as these are ephemeral, Flycheck won't check
   8743     ;; them anyway.
   8744     (flycheck-autoloads-file-p)
   8745     ;; Cask/Carton and dir-locals files contain data, not code, and don't need
   8746     ;; to follow Checkdoc conventions either.
   8747     (and (buffer-file-name)
   8748          (member (file-name-nondirectory (buffer-file-name))
   8749                  '("Cask" "Carton" ".dir-locals.el" ".dir-locals-2.el"))))))
   8750 
   8751 (defun flycheck--emacs-lisp-checkdoc-enabled-p ()
   8752   "Check whether to enable Emacs Lisp Checkdoc in the current buffer."
   8753   (and (flycheck--emacs-lisp-enabled-p)
   8754        ;; These files are valid Lisp, but don't contain "standard" comments.
   8755        (not (member (buffer-file-name) '("Eldev" "Eldev-local")))))
   8756 
   8757 (flycheck-define-checker emacs-lisp
   8758   "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler.
   8759 
   8760 See Info Node `(elisp)Byte Compilation'."
   8761   :command ("emacs" (eval flycheck-emacs-args)
   8762             (eval
   8763              (let ((path (pcase flycheck-emacs-lisp-load-path
   8764                            (`inherit load-path)
   8765                            (p (seq-map #'expand-file-name p)))))
   8766                (flycheck-prepend-with-option "--directory" path)))
   8767             (option "--eval" flycheck-emacs-lisp-package-user-dir nil
   8768                     flycheck-option-emacs-lisp-package-user-dir)
   8769             (option "--eval" flycheck-emacs-lisp-initialize-packages nil
   8770                     flycheck-option-emacs-lisp-package-initialize)
   8771             (option "--eval" flycheck-emacs-lisp-check-declare nil
   8772                     flycheck-option-emacs-lisp-check-declare)
   8773             "--eval" (eval (flycheck-emacs-lisp-bytecomp-config-form))
   8774             "--eval" (eval flycheck-emacs-lisp-check-form)
   8775             "--"
   8776             source-inplace)
   8777   :error-patterns
   8778   ((error line-start (file-name) ":" line ":" column ":"
   8779           (zero-or-more whitespace) "Error:" (zero-or-more whitespace)
   8780           (message (zero-or-more not-newline)
   8781                    (zero-or-more "\n    " (zero-or-more not-newline)))
   8782           line-end)
   8783    (warning line-start (file-name) ":" line ":" column ":"
   8784             (zero-or-more whitespace) "Warning:" (zero-or-more whitespace)
   8785             (message (zero-or-more not-newline)
   8786                      (zero-or-more "\n    " (zero-or-more not-newline)))
   8787             line-end)
   8788    (warning line-start (file-name) ":" line (optional ":" column) ":"
   8789             (zero-or-more whitespace) "Warning (check-declare): said\n"
   8790             (message (zero-or-more "    " (zero-or-more not-newline))
   8791                      (zero-or-more "\n    " (zero-or-more not-newline)))
   8792             line-end)
   8793    ;; The following is for Emacs 24 ‘check-declare-file’, which uses a
   8794    ;; less informative format.
   8795    (warning line-start "Warning (check-declare): " (file-name) " said "
   8796             (message (zero-or-more not-newline))
   8797             line-end))
   8798   :error-filter
   8799   (lambda (errors)
   8800     (flycheck-fill-empty-line-numbers
   8801      (flycheck-collapse-error-message-whitespace
   8802       (flycheck-sanitize-errors errors))))
   8803   :modes (emacs-lisp-mode lisp-interaction-mode)
   8804   :enabled flycheck--emacs-lisp-enabled-p
   8805   :predicate
   8806   (lambda ()
   8807     ;; Do not check buffers that should not be byte-compiled.  The checker
   8808     ;; process will refuse to compile these, which would confuse Flycheck
   8809     (not (bound-and-true-p no-byte-compile)))
   8810   :next-checkers (emacs-lisp-checkdoc))
   8811 
   8812 (defconst flycheck-emacs-lisp-checkdoc-form
   8813   (flycheck-prepare-emacs-lisp-form
   8814     (unless (require 'elisp-mode nil 'no-error)
   8815       ;; TODO: Fallback for Emacs 24, remove when dropping support for 24
   8816       (require 'lisp-mode))
   8817     (require 'checkdoc)
   8818 
   8819     (let ((source (car command-line-args-left))
   8820           ;; Remember the default directory of the process
   8821           (process-default-directory default-directory))
   8822       ;; Note that we deliberately use our custom approach even despite of
   8823       ;; `checkdoc-file' which was added to Emacs 25.1.  While it's conceptually
   8824       ;; the better thing, its implementation has too many flaws to be of use
   8825       ;; for us.
   8826       (with-temp-buffer
   8827         (insert-file-contents source 'visit)
   8828         (setq buffer-file-name source)
   8829         ;; And change back to the process default directory to make file-name
   8830         ;; back-substutition work
   8831         (setq default-directory process-default-directory)
   8832         (with-demoted-errors "Error in checkdoc: %S"
   8833           ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to
   8834           ;; parse sexps and identify docstrings correctly; see
   8835           ;; https://github.com/flycheck/flycheck/issues/833
   8836           (delay-mode-hooks (emacs-lisp-mode))
   8837           (setq delayed-mode-hooks nil)
   8838           (checkdoc-current-buffer t)
   8839           (with-current-buffer checkdoc-diagnostic-buffer
   8840             (princ (buffer-substring-no-properties (point-min) (point-max)))
   8841             (kill-buffer)))))))
   8842 
   8843 (defconst flycheck-emacs-lisp-checkdoc-variables
   8844   `(checkdoc-symbol-words
   8845     checkdoc-arguments-in-order-flag
   8846     checkdoc-force-history-flag
   8847     checkdoc-permit-comma-termination-flag
   8848     checkdoc-force-docstrings-flag
   8849     checkdoc-package-keywords-flag
   8850     checkdoc-spellcheck-documentation-flag
   8851     checkdoc-verb-check-experimental-flag
   8852     checkdoc-max-keyref-before-warn
   8853     sentence-end-double-space
   8854     ,@(and (>= emacs-major-version 28)
   8855            '(checkdoc-column-zero-backslash-before-paren)))
   8856   "Variables inherited by the checkdoc subprocess.")
   8857 
   8858 (defun flycheck-emacs-lisp-checkdoc-variables-form ()
   8859   "Make a sexp to pass relevant variables to a checkdoc subprocess.
   8860 
   8861 Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'."
   8862   `(progn
   8863      ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
   8864                 (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables))))
   8865 
   8866 (flycheck-define-checker emacs-lisp-checkdoc
   8867   "An Emacs Lisp style checker using CheckDoc.
   8868 
   8869 The checker runs `checkdoc-current-buffer'."
   8870   :command ("emacs" (eval flycheck-emacs-args)
   8871             "--eval" (eval (flycheck-sexp-to-string
   8872                             (flycheck-emacs-lisp-checkdoc-variables-form)))
   8873             "--eval" (eval flycheck-emacs-lisp-checkdoc-form)
   8874             "--" source)
   8875   :error-patterns
   8876   ((info line-start (file-name) ":" line ": " (message) line-end))
   8877   :modes (emacs-lisp-mode)
   8878   :enabled flycheck--emacs-lisp-checkdoc-enabled-p)
   8879 
   8880 (dolist (checker '(emacs-lisp emacs-lisp-checkdoc))
   8881   (setf (car (flycheck-checker-get checker 'command))
   8882         flycheck-this-emacs-executable))
   8883 
   8884 (defun flycheck-ember-template--check-for-config (&rest _ignored)
   8885   "Check the required config file is available up the file system."
   8886   (and buffer-file-name
   8887        (locate-dominating-file buffer-file-name ".template-lintrc.js")))
   8888 
   8889 (defun flycheck-ember-template--parse-error (output checker buffer)
   8890   "Parse Ember-template-lint errors/warnings from JSON OUTPUT.
   8891 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   8892 the BUFFER that was checked respectively."
   8893   (mapcar (lambda (err)
   8894             (let-alist err
   8895               (flycheck-error-new-at
   8896                .line
   8897                .column
   8898                (pcase .severity
   8899                  (2 'error)
   8900                  (1 'warning)
   8901                  (_ 'warning))
   8902                .message
   8903                :id .rule
   8904                :checker checker
   8905                :buffer buffer
   8906                :filename (buffer-file-name buffer))))
   8907           (cdr (car (car (flycheck-parse-json output))))))
   8908 
   8909 (flycheck-def-config-file-var flycheck-ember-template-lintrc
   8910     ember-template
   8911     ".template-lintrc.js")
   8912 
   8913 (flycheck-define-checker ember-template
   8914   "An Ember template checker using ember-template-lint."
   8915   :command ("ember-template-lint"
   8916             (config-file "--config-path" flycheck-ember-template-lintrc)
   8917             "--filename" source-original
   8918             "--format=json")
   8919   :standard-input t
   8920   :error-parser flycheck-ember-template--parse-error
   8921   :modes web-mode
   8922   :enabled flycheck-ember-template--check-for-config
   8923   :working-directory flycheck-ember-template--check-for-config)
   8924 
   8925 (flycheck-def-option-var flycheck-erlang-include-path nil erlang
   8926   "A list of include directories for Erlang.
   8927 
   8928 The value of this variable is a list of strings, where each
   8929 string is a directory to add to the include path of erlc.
   8930 Relative paths are relative to the file being checked."
   8931   :type '(repeat (directory :tag "Include directory"))
   8932   :safe #'flycheck-string-list-p
   8933   :package-version '(flycheck . "0.24"))
   8934 
   8935 (flycheck-def-option-var flycheck-erlang-library-path nil erlang
   8936   "A list of library directories for Erlang.
   8937 
   8938 The value of this variable is a list of strings, where each
   8939 string is a directory to add to the library path of erlc.
   8940 Relative paths are relative to the file being checked."
   8941   :type '(repeat (directory :tag "Library directory"))
   8942   :safe #'flycheck-string-list-p
   8943   :package-version '(flycheck . "0.24"))
   8944 
   8945 (flycheck-define-checker erlang
   8946   "An Erlang syntax checker using the Erlang interpreter.
   8947 
   8948 See URL `https://www.erlang.org/'."
   8949   :command ("erlc"
   8950             "-o" temporary-directory
   8951             (option-list "-I" flycheck-erlang-include-path)
   8952             (option-list "-pa" flycheck-erlang-library-path)
   8953             "-Wall"
   8954             source)
   8955   :error-patterns
   8956   ((warning line-start (file-name) ":" line ":" (optional column ":")
   8957             " Warning:" (message) line-end)
   8958    (error line-start (file-name) ":" line ":" (optional column ":") " "
   8959           (message) line-end))
   8960   :modes erlang-mode
   8961   :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name))))
   8962 
   8963 (defun flycheck--contains-rebar-config (dir-name)
   8964   "Return DIR-NAME if rebar config file exists in DIR-NAME, nil otherwise."
   8965   (when (or (file-exists-p (expand-file-name "rebar.config" dir-name))
   8966             (file-exists-p (expand-file-name "rebar.config.script" dir-name)))
   8967     dir-name))
   8968 
   8969 (defun flycheck--locate-rebar3-project-root
   8970     (file-name &optional prev-file-name acc)
   8971   "Find the top-most rebar project root for source FILE-NAME.
   8972 
   8973 A project root directory is any directory containing a
   8974 rebar.config file.  Find the top-most directory to move out of any
   8975 nested dependencies.
   8976 
   8977 FILE-NAME is a source file for which to find the project.
   8978 
   8979 PREV-FILE-NAME helps us prevent infinite looping
   8980 
   8981 ACC is an accumulator that keeps the list of results, the first
   8982 non-nil of which will be our project root.
   8983 
   8984 Return the absolute path to the directory"
   8985   (if (string= file-name prev-file-name)
   8986       (car (remove nil acc))
   8987     (let ((current-dir (file-name-directory file-name)))
   8988       (flycheck--locate-rebar3-project-root
   8989        (directory-file-name current-dir)
   8990        file-name
   8991        (cons (flycheck--contains-rebar-config current-dir) acc)))))
   8992 
   8993 (defun flycheck-rebar3-project-root (&optional _checker)
   8994   "Return directory where rebar.config is located."
   8995   (flycheck--locate-rebar3-project-root buffer-file-name))
   8996 
   8997 (flycheck-def-option-var flycheck-erlang-rebar3-profile nil erlang-rebar3
   8998   "The rebar3 profile to use.
   8999 
   9000 The profile used when compiling, if VALUE is nil \"test\" will be used
   9001 when the file is located in test directory, otherwise \"default\" will be
   9002 used as profile."
   9003   :type '(choice (const :tag "Automatic" nil)
   9004                  (string :tag "Profile"))
   9005   :safe #'flycheck-string-or-nil-p
   9006   :package-version '(flycheck . "32"))
   9007 
   9008 (defun flycheck-erlang-rebar3-get-profile ()
   9009   "Return rebar3 profile.
   9010 
   9011 Use flycheck-erlang-rebar3-profile if set, otherwise use test or eqc profile if
   9012 directory name is \"test\" or \"eqc\", or else \"default\"."
   9013   (or
   9014    flycheck-erlang-rebar3-profile
   9015    (with-no-warnings
   9016      ;; `seq-contains-p' is only in seq >= 2.21
   9017      (seq-contains '("test" "eqc")
   9018                    (and buffer-file-name
   9019                         (file-name-base
   9020                          (directory-file-name
   9021                           (file-name-directory buffer-file-name))))))
   9022    "default"))
   9023 
   9024 (flycheck-define-checker erlang-rebar3
   9025   "An Erlang syntax checker using the rebar3 build tool."
   9026   :command ("rebar3" "as" (eval (flycheck-erlang-rebar3-get-profile)) "compile")
   9027   :error-parser flycheck-parse-with-patterns-without-color
   9028   :error-patterns
   9029   ((warning line-start (file-name) ":" line ":" (optional column ":")
   9030             " Warning:" (message) line-end)
   9031    (error line-start (file-name) ":" line ":" (optional column ":") " "
   9032           (message) line-end))
   9033   :modes erlang-mode
   9034   :enabled flycheck-rebar3-project-root
   9035   :predicate flycheck-buffer-saved-p
   9036   :working-directory flycheck-rebar3-project-root)
   9037 
   9038 (flycheck-define-checker eruby-erubis
   9039   "An eRuby syntax checker using the `erubis' command.
   9040 
   9041 See URL `https://www.kuwata-lab.com/erubis/'."
   9042   :command ("erubis" "-z" source)
   9043   :error-patterns
   9044   ((error line-start (file-name) ":" line ": " (message) line-end))
   9045   :modes (html-erb-mode rhtml-mode)
   9046   :next-checkers ((warning . eruby-ruumba)))
   9047 
   9048 (flycheck-def-config-file-var flycheck-ruumbarc eruby-ruumba ".ruumba.yml")
   9049 
   9050 (flycheck-def-option-var flycheck-ruumba-lint-only nil eruby-ruumba
   9051   "Whether to only report code issues in Ruumba.
   9052 
   9053 When non-nil, only report code issues in Ruumba, via `--lint'.
   9054 Otherwise report style issues as well."
   9055   :safe #'booleanp
   9056   :type 'boolean
   9057   :package-version '(flycheck . "32"))
   9058 
   9059 (flycheck-define-checker eruby-ruumba
   9060   "An eRuby syntax and style checker using the Ruumba tool.
   9061 
   9062 You need at least Ruumba 0.1.7 for this syntax checker.
   9063 
   9064 See URL `https://github.com/ericqweinstein/ruumba'."
   9065   :command ("ruumba"
   9066             "--display-cop-names"
   9067             "--force-exclusion"
   9068             "--format" "emacs"
   9069             "--cache" "false"
   9070             (config-file "--config" flycheck-ruumbarc)
   9071             (option-flag "--lint" flycheck-ruumba-lint-only)
   9072             ;; Ruumba takes the original file name as argument when reading
   9073             ;; from standard input
   9074             "--stdin" source-original)
   9075   :standard-input t
   9076   :working-directory flycheck-ruby--find-project-root
   9077   :error-patterns
   9078   ((info line-start (file-name) ":" line ":" column ": C: "
   9079          (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
   9080    (warning line-start (file-name) ":" line ":" column ": W: "
   9081             (optional (id (one-or-more (not (any ":")))) ": ") (message)
   9082             line-end)
   9083    (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
   9084           (optional (id (one-or-more (not (any ":")))) ": ") (message)
   9085           line-end))
   9086   :modes (html-erb-mode rhtml-mode))
   9087 
   9088 (flycheck-def-args-var flycheck-gfortran-args fortran-gfortran
   9089   :package-version '(flycheck . "0.22"))
   9090 
   9091 (flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran
   9092   "A list of include directories for GCC Fortran.
   9093 
   9094 The value of this variable is a list of strings, where each
   9095 string is a directory to add to the include path of gcc.
   9096 Relative paths are relative to the file being checked."
   9097   :type '(repeat (directory :tag "Include directory"))
   9098   :safe #'flycheck-string-list-p
   9099   :package-version '(flycheck . "0.20"))
   9100 
   9101 (flycheck-def-option-var flycheck-gfortran-language-standard "f95"
   9102                          fortran-gfortran
   9103   "The language standard to use in GFortran.
   9104 
   9105 The value of this variable is either a string denoting a language
   9106 standard, or nil, to use the default standard.  When non-nil,
   9107 pass the language standard via the `-std' option."
   9108   :type '(choice (const :tag "Default standard" nil)
   9109                  (string :tag "Language standard"))
   9110   :package-version '(flycheck . "0.20"))
   9111 
   9112 (flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran
   9113   "The source code layout to use in GFortran.
   9114 
   9115 The value of this variable is one of the following symbols:
   9116 
   9117 nil
   9118      Let gfortran determine the layout from the extension
   9119 
   9120 `free'
   9121      Use free form layout
   9122 
   9123 
   9124 `fixed'
   9125      Use fixed form layout
   9126 
   9127 In any other case, an error is signaled."
   9128   :type '(choice (const :tag "Guess layout from extension" nil)
   9129                  (const :tag "Free form layout" free)
   9130                  (const :tag "Fixed form layout" fixed))
   9131   :safe (lambda (value) (or (not value) (memq value '(free fixed))))
   9132   :package-version '(flycheck . "0.20"))
   9133 
   9134 (defun flycheck-option-gfortran-layout (value)
   9135   "Option VALUE filter for `flycheck-gfortran-layout'."
   9136   (pcase value
   9137     (`nil nil)
   9138     (`free "free-form")
   9139     (`fixed "fixed-form")
   9140     (_ (error "Invalid value for flycheck-gfortran-layout: %S" value))))
   9141 
   9142 (flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra")
   9143                          fortran-gfortran
   9144   "A list of warnings for GCC Fortran.
   9145 
   9146 The value of this variable is a list of strings, where each string
   9147 is the name of a warning category to enable.  By default, all
   9148 recommended warnings and some extra warnings are enabled (as by
   9149 `-Wall' and `-Wextra' respectively).
   9150 
   9151 Refer to the gfortran manual at URL
   9152 `https://gcc.gnu.org/onlinedocs/gfortran/' for more information
   9153 about warnings"
   9154   :type '(choice (const :tag "No additional warnings" nil)
   9155                  (repeat :tag "Additional warnings"
   9156                          (string :tag "Warning name")))
   9157   :safe #'flycheck-string-list-p
   9158   :package-version '(flycheck . "0.20"))
   9159 
   9160 (flycheck-define-checker fortran-gfortran
   9161   "An Fortran syntax checker using GCC.
   9162 
   9163 Uses GCC's Fortran compiler gfortran.  See URL
   9164 `https://gcc.gnu.org/onlinedocs/gfortran/'."
   9165   :command ("gfortran"
   9166             "-fsyntax-only"
   9167             "-fshow-column"
   9168             ;; Do not visually indicate the source location
   9169             "-fno-diagnostics-show-caret"
   9170             ;; Do not show the corresponding warning group
   9171             "-fno-diagnostics-show-option"
   9172             ;; Fortran has similar include processing as C/C++
   9173             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   9174             (option "-std=" flycheck-gfortran-language-standard concat)
   9175             (option "-f" flycheck-gfortran-layout concat
   9176                     flycheck-option-gfortran-layout)
   9177             (option-list "-W" flycheck-gfortran-warnings concat)
   9178             (option-list "-I" flycheck-gfortran-include-path concat)
   9179             (eval flycheck-gfortran-args)
   9180             source)
   9181   :error-patterns
   9182   ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
   9183           (or (= 3 (zero-or-more not-newline) "\n") "")
   9184           (or "Error" "Fatal Error") ": "
   9185           (message) line-end)
   9186    (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
   9187             (or (= 3 (zero-or-more not-newline) "\n") "")
   9188             "Warning: " (message) line-end))
   9189   :modes (fortran-mode f90-mode))
   9190 
   9191 (flycheck-define-checker yaml-actionlint
   9192   "A YAML syntax checker using actionlint.
   9193 
   9194 See URL https://github.com/rhysd/actionlint/."
   9195   :command ("actionlint" "-oneline" source)
   9196   :error-patterns ((error line-start (file-name) ":" line ":" column ": " (message) line-end))
   9197   :modes (yaml-mode yaml-ts-mode))
   9198 
   9199 (flycheck-define-checker go-gofmt
   9200   "A Go syntax and style checker using the gofmt utility.
   9201 
   9202 See URL `https://golang.org/cmd/gofmt/'."
   9203   :command ("gofmt")
   9204   :standard-input t
   9205   :error-patterns
   9206   ((error line-start "<standard input>:" line ":" column ": "
   9207           (message) line-end))
   9208   :modes (go-mode go-ts-mode)
   9209   :next-checkers ((warning . go-vet)
   9210                   ;; Fall back, if go-vet doesn't exist
   9211                   (warning . go-build) (warning . go-test)
   9212                   (warning . go-errcheck)
   9213                   (warning . go-unconvert)
   9214                   (warning . go-staticcheck)))
   9215 
   9216 (flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet
   9217   "A list of print-like functions for `go vet'.
   9218 
   9219 Go vet will check these functions for format string problems and
   9220 issues, such as a mismatch between the number of formats used,
   9221 and the number of arguments given.
   9222 
   9223 Each entry is in the form Name:N where N is the zero-based
   9224 argument position of the first argument involved in the print:
   9225 either the format or the first print argument for non-formatted
   9226 prints.  For example, if you have Warn and Warnf functions that
   9227 take an io.Writer as their first argument, like Fprintf,
   9228 -printfuncs=Warn:1,Warnf:1 "
   9229   :type '(repeat :tag "print-like functions"
   9230                  (string :tag "function"))
   9231   :safe #'flycheck-string-list-p)
   9232 
   9233 (flycheck-define-checker go-vet
   9234   "A Go syntax checker using the `go vet' command.
   9235 
   9236 See URL `https://golang.org/cmd/go/' and URL
   9237 `https://golang.org/cmd/vet/'."
   9238   :command ("go" "vet"
   9239             (option "-printf.funcs=" flycheck-go-vet-print-functions concat
   9240                     flycheck-option-comma-separated-list)
   9241             (source ".go"))
   9242   :error-patterns
   9243   ((warning line-start (file-name) ":" line ": " (message) line-end))
   9244   :modes (go-mode go-ts-mode)
   9245   :next-checkers (go-build
   9246                   go-test
   9247                   ;; Fall back if `go build' or `go test' can be used
   9248                   go-errcheck
   9249                   go-unconvert
   9250                   go-staticcheck)
   9251   :verify (lambda (_)
   9252             (let* ((go (flycheck-checker-executable 'go-vet))
   9253                    (have-vet (member "vet" (ignore-errors
   9254                                              (process-lines go "tool")))))
   9255               (list
   9256                (flycheck-verification-result-new
   9257                 :label "go tool vet"
   9258                 :message (if have-vet "present" "missing")
   9259                 :face (if have-vet 'success '(bold error)))))))
   9260 
   9261 (flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test)
   9262   "Whether to install dependencies in `go build' and `go test'.
   9263 
   9264 If non-nil automatically install dependencies with `go build'
   9265 while syntax checking."
   9266   :type 'boolean
   9267   :safe #'booleanp
   9268   :package-version '(flycheck . "0.25"))
   9269 
   9270 (flycheck-def-option-var flycheck-go-build-tags nil
   9271                          (go-build go-test go-errcheck go-staticcheck)
   9272   "A list of tags for `go build'.
   9273 
   9274 Each item is a string with a tag to be given to `go build'."
   9275   :type '(repeat (string :tag "Tag"))
   9276   :safe #'flycheck-string-list-p
   9277   :package-version '(flycheck . "0.25"))
   9278 
   9279 
   9280 (flycheck-def-option-var flycheck-go-version nil go-staticcheck
   9281   "The version of go that should be targeted by `staticcheck'.
   9282 
   9283 Should be a string representing a version, like 1.6 or 1.11.4.
   9284 See `https://staticcheck.io/docs/#targeting-go-versions' for
   9285 details."
   9286   :type '(choice (const :tag "Unspecified" nil)
   9287                  (string :tag "Version"))
   9288   :safe #'flycheck-string-or-nil-p
   9289   :package-version '(flycheck . "0.32"))
   9290 
   9291 (flycheck-define-checker go-build
   9292   "A Go syntax and type checker using the `go build' command.
   9293 
   9294 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
   9295   :command ("go" "build"
   9296             (option-flag "-i" flycheck-go-build-install-deps)
   9297             ;; multiple tags are listed as "dev debug ..."
   9298             (option-list "-tags=" flycheck-go-build-tags concat)
   9299             "-o" null-device)
   9300   :error-patterns
   9301   ((error line-start (file-name) ":" line ":"
   9302           (optional column ":") " "
   9303           (message (one-or-more not-newline)
   9304                    (zero-or-more "\n\t" (one-or-more not-newline)))
   9305           line-end)
   9306    ;; Catch error message about multiple packages in a directory, which doesn't
   9307    ;; follow the standard error message format.
   9308    (info line-start
   9309          (message "can't load package: package "
   9310                   (one-or-more (not (any ?: ?\n)))
   9311                   ": found packages "
   9312                   (one-or-more not-newline))
   9313          line-end))
   9314   :error-filter
   9315   (lambda (errors)
   9316     (dolist (error errors)
   9317       (unless (flycheck-error-line error)
   9318         ;; Flycheck ignores errors without line numbers, but the error
   9319         ;; message about multiple packages in a directory doesn't come with a
   9320         ;; line number, so inject a fake one.
   9321         (setf (flycheck-error-line error) 1)))
   9322     errors)
   9323   :modes (go-mode go-ts-mode)
   9324   :predicate (lambda ()
   9325                (and (flycheck-buffer-saved-p)
   9326                     (not (string-suffix-p "_test.go" (buffer-file-name)))))
   9327   :next-checkers ((warning . go-errcheck)
   9328                   (warning . go-unconvert)
   9329                   (warning . go-staticcheck)))
   9330 
   9331 (flycheck-define-checker go-test
   9332   "A Go syntax and type checker using the `go test' command.
   9333 
   9334 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
   9335   :command ("go" "test"
   9336             (option-flag "-i" flycheck-go-build-install-deps)
   9337             (option-list "-tags=" flycheck-go-build-tags concat)
   9338             "-c" "-o" null-device)
   9339   :error-patterns
   9340   ((error line-start (file-name) ":" line ":"
   9341           (optional column ":") " "
   9342           (message (one-or-more not-newline)
   9343                    (zero-or-more "\n\t" (one-or-more not-newline)))
   9344           line-end))
   9345   :modes (go-mode go-ts-mode)
   9346   :predicate
   9347   (lambda () (and (flycheck-buffer-saved-p)
   9348                   (string-suffix-p "_test.go" (buffer-file-name))))
   9349   :next-checkers ((warning . go-errcheck)
   9350                   (warning . go-unconvert)
   9351                   (warning . go-staticcheck)))
   9352 
   9353 (flycheck-define-checker go-errcheck
   9354   "A Go checker for unchecked errors.
   9355 
   9356 Requires errcheck newer than commit 8515d34 (Aug 28th, 2015).
   9357 
   9358 See URL `https://github.com/kisielk/errcheck'."
   9359   :command ("errcheck"
   9360             "-abspath"
   9361             (option-list "-tags=" flycheck-go-build-tags concat)
   9362             ".")
   9363   :error-patterns
   9364   ((warning line-start
   9365             (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t")
   9366             (message)
   9367             line-end))
   9368   :error-filter
   9369   (lambda (errors)
   9370     (let ((errors (flycheck-sanitize-errors errors)))
   9371       (dolist (err errors)
   9372         (when-let (message (flycheck-error-message err))
   9373           ;; Improve the messages reported by errcheck to make them more clear.
   9374           (setf (flycheck-error-message err)
   9375                 (format "Ignored `error` returned from `%s`" message)))))
   9376     errors)
   9377   :modes (go-mode go-ts-mode)
   9378   :predicate (lambda () (flycheck-buffer-saved-p))
   9379   :next-checkers ((warning . go-unconvert)
   9380                   (warning . go-staticcheck)))
   9381 
   9382 (flycheck-define-checker go-unconvert
   9383   "A Go checker looking for unnecessary type conversions.
   9384 
   9385 See URL `https://github.com/mdempsky/unconvert'."
   9386   :command ("unconvert" ".")
   9387   :error-patterns
   9388   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
   9389   :modes (go-mode go-ts-mode)
   9390   :predicate (lambda () (flycheck-buffer-saved-p)))
   9391 
   9392 (flycheck-define-checker go-staticcheck
   9393   "A Go checker that performs static analysis and linting using
   9394 the `staticcheck' command.
   9395 
   9396 `staticcheck' is explicitly fully compatible with \"the last two
   9397 versions of go\". `staticheck' can target earlier versions (with
   9398 limited features) if `flycheck-go-version' is set. See URL
   9399 `https://staticcheck.io/'."
   9400   :command ("staticcheck" "-f" "json"
   9401             (option-list "-tags" flycheck-go-build-tags concat)
   9402             (option "-go" flycheck-go-version))
   9403 
   9404   :error-parser flycheck-parse-go-staticcheck
   9405   :modes (go-mode go-ts-mode))
   9406 
   9407 (flycheck-define-checker groovy
   9408   "A groovy syntax checker using groovy compiler API.
   9409 
   9410 See URL `https://www.groovy-lang.org'."
   9411   :command ("groovy" "-e"
   9412             "import org.codehaus.groovy.control.*
   9413 
   9414 unit = new CompilationUnit()
   9415 unit.addSource(\"input\", System.in)
   9416 
   9417 try {
   9418     unit.compile(Phases.CONVERSION)
   9419 } catch (MultipleCompilationErrorsException e) {
   9420     e.errorCollector.write(new PrintWriter(System.out, true), null)
   9421 }")
   9422   :standard-input t
   9423   :error-patterns
   9424   ((error line-start "input: " line ":" (message)
   9425           " @ line " line ", column " column "." line-end))
   9426   :modes groovy-mode)
   9427 
   9428 (flycheck-define-checker haml
   9429   "A Haml syntax checker using the Haml compiler.
   9430 
   9431 See URL `https://haml.info'."
   9432   :command ("haml" "-c" "--stdin")
   9433   :standard-input t
   9434   :error-patterns
   9435   ((error line-start "Syntax error on line " line ": " (message) line-end)
   9436    (error line-start ":" line ": syntax error, " (message) line-end))
   9437   :modes haml-mode)
   9438 
   9439 (flycheck-define-checker haml-lint
   9440   "HAML-Lint style checker.
   9441 
   9442 See URL `https://github.com/sds/haml-lint'."
   9443   :command ("haml-lint" "--no-color" "--no-summary" source)
   9444   :error-patterns
   9445   ((error line-start (file-name) ":" line " [E]" (message) line-end)
   9446    (warning line-start (file-name) ":" line " [W]" (message) line-end))
   9447   :modes haml-mode)
   9448 
   9449 (flycheck-define-checker handlebars
   9450   "A Handlebars syntax checker using the Handlebars compiler.
   9451 
   9452 See URL `https://handlebarsjs.com/'."
   9453   :command ("handlebars" "-i-")
   9454   :standard-input t
   9455   :error-patterns
   9456   ((error line-start
   9457           "Error: Parse error on line " line ":" (optional "\r") "\n"
   9458           (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n"
   9459           (message) line-end))
   9460   :modes (handlebars-mode handlebars-sgml-mode web-mode)
   9461   :predicate
   9462   (lambda ()
   9463     (if (eq major-mode 'web-mode)
   9464         ;; Check if this is a handlebars file since web-mode does not store the
   9465         ;; non-canonical engine name
   9466         (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps))
   9467                (pattern (cdr (assoc "handlebars" regexp-alist))))
   9468           (and pattern (buffer-file-name)
   9469                (string-match-p pattern (buffer-file-name))))
   9470       t)))
   9471 
   9472 (defconst flycheck-haskell-module-re
   9473   (rx line-start (zero-or-more (or "\n" (any space)))
   9474       "module" (one-or-more (or "\n" (any space)))
   9475       (group (one-or-more (not (any space "(" "\n")))))
   9476   "Regular expression for a Haskell module name.")
   9477 
   9478 (flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc)
   9479   :package-version '(flycheck . "0.22"))
   9480 
   9481 (flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc
   9482   "Whether to enable nix support in stack.
   9483 
   9484 When non-nil, stack will append '--nix' flag to any call."
   9485   :type 'boolean
   9486   :safe #'booleanp
   9487   :package-version '(flycheck . "26"))
   9488 
   9489 (flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc
   9490   "Override project stack.yaml file.
   9491 
   9492 The value of this variable is a file path that refers to a yaml
   9493 file for the current stack project. Relative file paths are
   9494 resolved against the checker's working directory. When non-nil,
   9495 stack will get overridden value via `--stack-yaml'."
   9496   :type '(choice (const :tag "Unspecified" nil)
   9497                  (file :tag "Project file"))
   9498   :safe #'flycheck-string-or-nil-p
   9499   :package-version '(flycheck . "32"))
   9500 
   9501 (flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc
   9502   "Whether to disable the user package database in GHC.
   9503 
   9504 When non-nil, disable the user package database in GHC, via
   9505 `-no-user-package-db'."
   9506   :type 'boolean
   9507   :safe #'booleanp
   9508   :package-version '(flycheck . "0.16"))
   9509 
   9510 (flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc
   9511   "Additional module databases for GHC.
   9512 
   9513 The value of this variable is a list of strings, where each
   9514 string is a directory of a package database.  Each package
   9515 database is given to GHC via `-package-db'."
   9516   :type '(repeat (directory :tag "Package database"))
   9517   :safe #'flycheck-string-list-p
   9518   :package-version '(flycheck . "0.16"))
   9519 
   9520 (flycheck-def-option-var flycheck-ghc-search-path nil
   9521                          (haskell-stack-ghc haskell-ghc)
   9522   "Module search path for (Stack) GHC.
   9523 
   9524 The value of this variable is a list of strings, where each
   9525 string is a directory containing Haskell modules.  Each directory
   9526 is added to the GHC search path via `-i'."
   9527   :type '(repeat (directory :tag "Module directory"))
   9528   :safe #'flycheck-string-list-p
   9529   :package-version '(flycheck . "0.16"))
   9530 
   9531 (flycheck-def-option-var flycheck-ghc-language-extensions nil
   9532                          (haskell-stack-ghc haskell-ghc)
   9533   "Language extensions for (Stack) GHC.
   9534 
   9535 The value of this variable is a list of strings, where each
   9536 string is a Haskell language extension, as in the LANGUAGE
   9537 pragma.  Each extension is enabled via `-X'."
   9538   :type '(repeat (string :tag "Language extension"))
   9539   :safe #'flycheck-string-list-p
   9540   :package-version '(flycheck . "0.19"))
   9541 
   9542 (defvar flycheck-haskell-ghc-cache-directory nil
   9543   "The cache directory for `ghc' output.")
   9544 
   9545 (defun flycheck-haskell-ghc-cache-directory ()
   9546   "Get the cache location for `ghc' output.
   9547 
   9548 If no cache directory exists yet, create one and return it.
   9549 Otherwise return the previously used cache directory."
   9550   (setq flycheck-haskell-ghc-cache-directory
   9551         (or flycheck-haskell-ghc-cache-directory
   9552             (make-temp-file "flycheck-haskell-ghc-cache" 'directory))))
   9553 
   9554 (defun flycheck--locate-dominating-file-matching (directory regexp)
   9555   "Search for a file in directory hierarchy starting at DIRECTORY.
   9556 
   9557 Look up the directory hierarchy from DIRECTORY for a directory
   9558 containing a file that matches REGEXP."
   9559   (locate-dominating-file
   9560    directory
   9561    (lambda (dir)
   9562      (directory-files dir nil regexp t))))
   9563 
   9564 (defun flycheck-haskell--find-stack-default-directory ()
   9565   "Find a directory to run haskell-stack-ghc.
   9566 
   9567 Return a parent directory with a stack*.y[a]ml file, or the
   9568 directory returned by \"stack path --project-root\"."
   9569   (or
   9570    (when (buffer-file-name)
   9571      (flycheck--locate-dominating-file-matching
   9572       (file-name-directory (buffer-file-name))
   9573       (rx "stack" (* any) "." (or "yml" "yaml") eos)))
   9574    (when-let* ((stack (funcall flycheck-executable-find "stack"))
   9575                (output (ignore-errors
   9576                          (process-lines stack
   9577                                         "--no-install-ghc"
   9578                                         "path" "--project-root")))
   9579                (stack-dir (car output)))
   9580      (and (file-directory-p stack-dir) stack-dir))))
   9581 
   9582 (defun flycheck-haskell--ghc-find-default-directory (_checker)
   9583   "Find a parent directory containing a cabal or package.yaml file."
   9584   (when (buffer-file-name)
   9585     (flycheck--locate-dominating-file-matching
   9586      (file-name-directory (buffer-file-name))
   9587      "\\.cabal\\'\\|\\`package\\.yaml\\'")))
   9588 
   9589 (flycheck-define-checker haskell-stack-ghc
   9590   "A Haskell syntax and type checker using `stack ghc'.
   9591 
   9592 See URL `https://github.com/commercialhaskell/stack'."
   9593   :command ("stack"
   9594             "--no-install-ghc"
   9595             (option "--stack-yaml" flycheck-ghc-stack-project-file)
   9596             (option-flag "--nix" flycheck-ghc-stack-use-nix)
   9597             "ghc" "--" "-Wall" "-no-link"
   9598             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
   9599             (option-list "-X" flycheck-ghc-language-extensions concat)
   9600             (option-list "-i" flycheck-ghc-search-path concat)
   9601             (eval (concat
   9602                    "-i"
   9603                    (flycheck-module-root-directory
   9604                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
   9605             (eval flycheck-ghc-args)
   9606             "-x" (eval
   9607                   (pcase major-mode
   9608                     (`haskell-mode "hs")
   9609                     (`haskell-literate-mode "lhs")))
   9610             source)
   9611   :error-patterns
   9612   ((warning line-start (file-name) ":" line ":" column ":"
   9613             (or " " "\n    ") (in "Ww") "arning:"
   9614             (optional " " "[" (id (one-or-more not-newline)) "]")
   9615             (optional "\n")
   9616             (message
   9617              (one-or-more " ") (one-or-more not-newline)
   9618              (zero-or-more "\n"
   9619                            (one-or-more " ")
   9620                            (one-or-more (not (any ?\n ?|)))))
   9621             line-end)
   9622    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
   9623           (optional " " "[" (id (one-or-more not-newline)) "]")
   9624           (or (message (one-or-more not-newline))
   9625               (and "\n"
   9626                    (message
   9627                     (one-or-more " ") (one-or-more not-newline)
   9628                     (zero-or-more "\n"
   9629                                   (one-or-more " ")
   9630                                   (one-or-more (not (any ?\n ?|)))))))
   9631           line-end))
   9632   :error-filter
   9633   (lambda (errors)
   9634     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
   9635   :modes (haskell-mode haskell-literate-mode)
   9636   :next-checkers ((warning . haskell-hlint))
   9637   :working-directory (lambda (_)
   9638                        (flycheck-haskell--find-stack-default-directory))
   9639   :enabled flycheck-haskell--find-stack-default-directory
   9640   :verify (lambda (_)
   9641             (let* ((stack (flycheck-haskell--find-stack-default-directory)))
   9642               (list
   9643                (flycheck-verification-result-new
   9644                 :label "stack config"
   9645                 :message (or stack "Not found")
   9646                 :face (if stack 'success '(bold error)))))))
   9647 
   9648 (flycheck-define-checker haskell-ghc
   9649   "A Haskell syntax and type checker using ghc.
   9650 
   9651 See URL `https://www.haskell.org/ghc/'."
   9652   :command ("ghc" "-Wall" "-no-link"
   9653             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
   9654             (option-flag "-no-user-package-db"
   9655                          flycheck-ghc-no-user-package-database)
   9656             (option-list "-package-db" flycheck-ghc-package-databases)
   9657             (option-list "-i" flycheck-ghc-search-path concat)
   9658             ;; Include the parent directory of the current module tree, to
   9659             ;; properly resolve local imports
   9660             (eval (concat
   9661                    "-i"
   9662                    (flycheck-module-root-directory
   9663                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
   9664             (option-list "-X" flycheck-ghc-language-extensions concat)
   9665             (eval flycheck-ghc-args)
   9666             "-x" (eval
   9667                   (pcase major-mode
   9668                     (`haskell-mode "hs")
   9669                     (`haskell-literate-mode "lhs")))
   9670             source)
   9671   :error-patterns
   9672   ((warning line-start (file-name) ":" line ":" column ":"
   9673             (or " " "\n    ") (in "Ww") "arning:"
   9674             (optional " " "[" (id (one-or-more not-newline)) "]")
   9675             (optional "\n")
   9676             (message
   9677              (one-or-more " ") (one-or-more not-newline)
   9678              (zero-or-more "\n"
   9679                            (one-or-more " ")
   9680                            (one-or-more (not (any ?\n ?|)))))
   9681             line-end)
   9682    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
   9683           (optional " " "[" (id (one-or-more not-newline)) "]")
   9684           (or (message (one-or-more not-newline))
   9685               (and "\n"
   9686                    (message
   9687                     (one-or-more " ") (one-or-more not-newline)
   9688                     (zero-or-more "\n"
   9689                                   (one-or-more " ")
   9690                                   (one-or-more (not (any ?\n ?|)))))))
   9691           line-end))
   9692   :error-filter
   9693   (lambda (errors)
   9694     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
   9695   :modes (haskell-mode haskell-literate-mode)
   9696   :next-checkers ((warning . haskell-hlint))
   9697   :working-directory flycheck-haskell--ghc-find-default-directory)
   9698 
   9699 (flycheck-def-config-file-var flycheck-hlintrc haskell-hlint "HLint.hs")
   9700 
   9701 (flycheck-def-args-var flycheck-hlint-args haskell-hlint
   9702   :package-version '(flycheck . "0.25"))
   9703 
   9704 (flycheck-def-option-var flycheck-hlint-language-extensions
   9705     nil haskell-hlint
   9706   "Extensions list to enable for hlint.
   9707 
   9708 The value of this variable is a list of strings, where each
   9709 string is a name of extension to enable in
   9710 hlint (e.g. \"QuasiQuotes\")."
   9711   :type '(repeat :tag "Extensions" (string :tag "Extension"))
   9712   :safe #'flycheck-string-list-p
   9713   :package-version '(flycheck . "0.24"))
   9714 
   9715 (flycheck-def-option-var flycheck-hlint-ignore-rules
   9716     nil haskell-hlint
   9717   "Ignore rules list for hlint checks.
   9718 
   9719 The value of this variable is a list of strings, where each
   9720 string is an ignore rule (e.g. \"Use fmap\")."
   9721   :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule"))
   9722   :safe #'flycheck-string-list-p
   9723   :package-version '(flycheck . "0.24"))
   9724 
   9725 (flycheck-def-option-var flycheck-hlint-hint-packages
   9726     nil haskell-hlint
   9727   "Hint packages to include for hlint checks.
   9728 
   9729 The value of this variable is a list of strings, where each
   9730 string is a default hint package (e.g. (\"Generalise\"
   9731 \"Default\" \"Dollar\"))."
   9732   :type '(repeat :tag "Hint packages" (string :tag "Hint package"))
   9733   :safe #'flycheck-string-list-p
   9734   :package-version '(flycheck . "0.24"))
   9735 
   9736 (flycheck-define-checker haskell-hlint
   9737   "A Haskell style checker using hlint.
   9738 
   9739 See URL `https://github.com/ndmitchell/hlint'."
   9740   :command ("hlint"
   9741             (option-list "-X" flycheck-hlint-language-extensions concat)
   9742             (option-list "-i=" flycheck-hlint-ignore-rules concat)
   9743             (option-list "-h" flycheck-hlint-hint-packages concat)
   9744             (config-file "-h" flycheck-hlintrc)
   9745             (eval flycheck-hlint-args)
   9746             source-inplace)
   9747   :error-patterns
   9748   ((info line-start
   9749          (file-name) ":"
   9750          (or (seq line ":" column (optional "-" end-column))
   9751              (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9752          ": Suggestion: "
   9753          (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9754          line-end)
   9755    (warning line-start
   9756             (file-name) ":"
   9757             (or (seq line ":" column (optional "-" end-column))
   9758                 (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9759             ": Warning: "
   9760             (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9761             line-end)
   9762    (error line-start
   9763           (file-name) ":"
   9764           (or (seq line ":" column (optional "-" end-column))
   9765               (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9766           ": Error: "
   9767           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9768           line-end))
   9769   :modes (haskell-mode haskell-literate-mode))
   9770 
   9771 (flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc")
   9772 
   9773 (flycheck-define-checker html-tidy
   9774   "A HTML syntax and style checker using Tidy.
   9775 
   9776 See URL `https://github.com/htacg/tidy-html5'."
   9777   :command ("tidy" (config-file "-config" flycheck-tidyrc)
   9778             "-lang" "en"
   9779             "-e" "-q")
   9780   :standard-input t
   9781   :error-patterns
   9782   ((error line-start
   9783           "line " line
   9784           " column " column
   9785           " - Error: " (message) line-end)
   9786    (warning line-start
   9787             "line " line
   9788             " column " column
   9789             " - Warning: " (message) line-end))
   9790   :modes (html-mode mhtml-mode nxhtml-mode))
   9791 
   9792 (flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc")
   9793 
   9794 (flycheck-def-option-var flycheck-jshint-extract-javascript nil
   9795                          javascript-jshint
   9796   "Whether jshint should extract Javascript from HTML.
   9797 
   9798 If nil no extract rule is given to jshint.  If `auto' only
   9799 extract Javascript if a HTML file is detected.  If `always' or
   9800 `never' extract Javascript always or never respectively.
   9801 
   9802 Refer to the jshint manual at the URL
   9803 `https://jshint.com/docs/cli/#flags' for more information."
   9804   :type
   9805   '(choice (const :tag "No extraction rule" nil)
   9806            (const :tag "Try to extract Javascript when detecting HTML files"
   9807                   auto)
   9808            (const :tag "Always try to extract Javascript" always)
   9809            (const :tag "Never try to extract Javascript" never))
   9810   :safe #'symbolp
   9811   :package-version '(flycheck . "26"))
   9812 
   9813 (flycheck-define-checker javascript-jshint
   9814   "A Javascript syntax and style checker using jshint.
   9815 
   9816 See URL `https://www.jshint.com'."
   9817   :command ("jshint" "--reporter=checkstyle"
   9818             "--filename" source-original
   9819             (config-file "--config" flycheck-jshintrc)
   9820             (option "--extract=" flycheck-jshint-extract-javascript
   9821                     concat flycheck-option-symbol)
   9822             "-")
   9823   :standard-input t
   9824   :error-parser flycheck-parse-checkstyle
   9825   :error-filter
   9826   (lambda (errors)
   9827     (flycheck-remove-error-file-names
   9828      "stdin" (flycheck-dequalify-error-ids errors)))
   9829   :modes (js-mode js2-mode js3-mode rjsx-mode js-ts-mode))
   9830 
   9831 (flycheck-def-args-var flycheck-eslint-args javascript-eslint
   9832   :package-version '(flycheck . "32"))
   9833 
   9834 (flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint
   9835   "A list of directories with custom rules for ESLint.
   9836 
   9837 The value of this variable is a list of strings, where each
   9838 string is a directory with custom rules for ESLint.
   9839 
   9840 Refer to the ESLint manual at URL
   9841 `https://eslint.org/docs/user-guide/command-line-interface#--rulesdir'
   9842 for more information about the custom directories."
   9843   :type '(repeat (directory :tag "Custom rules directory"))
   9844   :safe #'flycheck-string-list-p
   9845   :package-version '(flycheck . "29"))
   9846 
   9847 (defun flycheck-eslint-config-exists-p ()
   9848   "Whether there is a valid eslint config for the current buffer."
   9849   (eql 0 (flycheck-call-checker-process
   9850           'javascript-eslint nil nil nil
   9851           "--print-config" (or buffer-file-name "index.js"))))
   9852 
   9853 (defun flycheck-parse-eslint (output checker buffer)
   9854   "Parse ESLint errors/warnings from JSON OUTPUT.
   9855 
   9856 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   9857 the BUFFER that was checked respectively.
   9858 
   9859 See URL `https://eslint.org' for more information about ESLint."
   9860   (mapcar (lambda (err)
   9861             (let-alist err
   9862               (flycheck-error-new-at
   9863                .line
   9864                .column
   9865                (pcase .severity
   9866                  (2 'error)
   9867                  (1 'warning)
   9868                  (_ 'warning))
   9869                .message
   9870                :id .ruleId
   9871                :checker checker
   9872                :buffer buffer
   9873                :filename (buffer-file-name buffer)
   9874                :end-line .endLine
   9875                :end-column .endColumn)))
   9876           (let-alist (caar (flycheck-parse-json output))
   9877             .messages)))
   9878 
   9879 (defun flycheck-eslint--find-working-directory (_checker)
   9880   "Look for a working directory to run ESLint CHECKER in.
   9881 
   9882 This will be the directory that contains the `node_modules'
   9883 directory.  If no such directory is found in the directory
   9884 hierarchy, it looks first for `.eslintignore' and then for
   9885 `.eslintrc' files to detect the project root."
   9886   (let* ((regex-config (concat "\\`\\.eslintrc"
   9887                                "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'")))
   9888     (when buffer-file-name
   9889       (or (locate-dominating-file buffer-file-name "node_modules")
   9890           (locate-dominating-file buffer-file-name ".eslintignore")
   9891           (locate-dominating-file
   9892            (file-name-directory buffer-file-name)
   9893            (lambda (directory)
   9894              (> (length (directory-files directory nil regex-config t)) 0)))))))
   9895 
   9896 (flycheck-define-checker javascript-eslint
   9897   "A Javascript syntax and style checker using eslint.
   9898 
   9899 See URL `https://eslint.org/'."
   9900   :command ("eslint" "--format=json"
   9901             (option-list "--rulesdir" flycheck-eslint-rules-directories)
   9902             (eval flycheck-eslint-args)
   9903             "--stdin" "--stdin-filename" source-original)
   9904   :standard-input t
   9905   :error-parser flycheck-parse-eslint
   9906   :enabled (lambda () (flycheck-eslint-config-exists-p))
   9907   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
   9908                   typescript-mode js-ts-mode typescript-ts-mode tsx-ts-mode)
   9909   :working-directory flycheck-eslint--find-working-directory
   9910   :verify
   9911   (lambda (_)
   9912     (let* ((default-directory
   9913              (flycheck-compute-working-directory 'javascript-eslint))
   9914            (have-config (flycheck-eslint-config-exists-p)))
   9915       (list
   9916        (flycheck-verification-result-new
   9917         :label "config file"
   9918         :message (if have-config "found" "missing or incorrect")
   9919         :face (if have-config 'success '(bold error))))))
   9920   :error-explainer
   9921   (lambda (err)
   9922     (let ((error-code (flycheck-error-id err))
   9923           (url "https://eslint.org/docs/rules/%s"))
   9924       (and error-code
   9925            ;; skip non-builtin rules
   9926            (not ;; `seq-contains-p' is only in seq >= 2.21
   9927             (with-no-warnings (seq-contains error-code ?/)))
   9928            `(url . ,(format url error-code))))))
   9929 
   9930 (flycheck-define-checker javascript-standard
   9931   "A Javascript code and style checker for the (Semi-)Standard Style.
   9932 
   9933 This checker works with `standard' and `semistandard', defaulting
   9934 to the former.  To use it with the latter, set
   9935 `flycheck-javascript-standard-executable' to `semistandard'.
   9936 
   9937 See URL `https://github.com/standard/standard' and URL
   9938 `https://github.com/Flet/semistandard'."
   9939   :command ("standard" "--stdin")
   9940   :standard-input t
   9941   :error-patterns
   9942   ((error line-start "  <text>:" line ":" column ":" (message) line-end))
   9943   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
   9944                   js-ts-mode))
   9945 
   9946 (flycheck-define-checker json-jsonlint
   9947   "A JSON syntax and style checker using jsonlint.
   9948 
   9949 See URL `https://github.com/zaach/jsonlint'."
   9950   ;; We can't use standard input for jsonlint, because it doesn't output errors
   9951   ;; anymore when using -c -q with standard input :/
   9952   :command ("jsonlint" "-c" "-q" source)
   9953   :error-patterns
   9954   ((error line-start
   9955           (file-name)
   9956           ": line " line
   9957           ", col " column ", "
   9958           (message) line-end))
   9959   :error-filter
   9960   (lambda (errors)
   9961     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
   9962   :modes (json-mode js-json-mode json-ts-mode))
   9963 
   9964 (flycheck-define-checker json-python-json
   9965   "A JSON syntax checker using Python json.tool module.
   9966 
   9967 See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'."
   9968   :command ("python3" "-m" "json.tool" source
   9969             ;; Send the pretty-printed output to the null device
   9970             null-device)
   9971   :error-patterns
   9972   ((error line-start
   9973           (message) ": line " line " column " column
   9974           ;; Ignore the rest of the line which shows the char position.
   9975           (one-or-more not-newline)
   9976           line-end))
   9977   :modes (json-mode js-json-mode json-ts-mode)
   9978   ;; The JSON parser chokes if the buffer is empty and has no JSON inside
   9979   :predicate flycheck-buffer-nonempty-p)
   9980 
   9981 (flycheck-define-checker json-jq
   9982   "JSON checker using the jq tool.
   9983 
   9984 This checker accepts multiple consecutive JSON values in a
   9985 single input, which is useful for jsonlines data.
   9986 
   9987 See URL `https://stedolan.github.io/jq/'."
   9988   :command ("jq" "." source null-device)
   9989   ;; Example error message:
   9990   ;;   parse error: Expected another key-value pair at line 3, column 1
   9991   :error-patterns
   9992   ((error line-start
   9993           (optional "parse error: ")
   9994           (message) "at line " line ", column " column
   9995           (zero-or-more not-newline) line-end))
   9996   :modes (json-mode js-json-mode json-ts-mode))
   9997 
   9998 (flycheck-define-checker jsonnet
   9999   "A Jsonnet syntax checker using the jsonnet binary.
  10000 
  10001 See URL `https://jsonnet.org'."
  10002   :command ("jsonnet" source-inplace)
  10003   :error-patterns
  10004   ((error line-start "STATIC ERROR: " (file-name) ":"
  10005           (or (seq line ":" column (zero-or-one (seq "-" end-column)))
  10006               (seq "(" line ":" column ")" "-"
  10007                    "(" end-line ":" end-column ")"))
  10008           ": " (message) line-end)
  10009    (error line-start "RUNTIME ERROR: " (message) "\n"
  10010           (? "\t" (file-name) ":" ;; first line of the backtrace
  10011              (or (seq line ":" column (zero-or-one (seq "-" end-column)))
  10012                  (seq "(" line ":" column ")" "-"
  10013                       "(" end-line ":" end-column ")")))))
  10014   :error-filter
  10015   (lambda (errs)
  10016     ;; Some errors are missing line numbers. See URL
  10017     ;; `https://github.com/google/jsonnet/issues/786'.
  10018     (dolist (err errs)
  10019       (unless (flycheck-error-line err)
  10020         (setf (flycheck-error-line err) 1)))
  10021     (flycheck-sanitize-errors errs))
  10022   :modes jsonnet-mode)
  10023 
  10024 (flycheck-define-checker less
  10025   "A LESS syntax checker using lessc.
  10026 
  10027 Requires lessc 1.4 or newer.
  10028 
  10029 See URL `https://lesscss.org'."
  10030   :command ("lessc" "--lint" "--no-color"
  10031             "-")
  10032   :standard-input t
  10033   :error-patterns
  10034   ((error line-start (one-or-more word) ":"
  10035           (message)
  10036           " in - on line " line
  10037           ", column " column ":"
  10038           line-end))
  10039   :modes less-css-mode)
  10040 
  10041 (flycheck-define-checker less-stylelint
  10042   "A LESS syntax and style checker using stylelint.
  10043 
  10044 See URL `https://stylelint.io/'."
  10045   :command ("stylelint"
  10046             (eval flycheck-stylelint-args)
  10047             (option-flag "--quiet" flycheck-stylelint-quiet)
  10048             (config-file "--config" flycheck-stylelintrc))
  10049   :standard-input t
  10050   :verify (lambda (_) (flycheck--stylelint-verify 'less-stylelint))
  10051   :error-parser flycheck-parse-stylelint
  10052   :predicate flycheck-buffer-nonempty-p
  10053   :modes (less-css-mode))
  10054 
  10055 (flycheck-define-checker llvm-llc
  10056   "Flycheck LLVM IR checker using llc.
  10057 
  10058 See URL `https://llvm.org/docs/CommandGuide/llc.html'."
  10059   :command ("llc" "-o" null-device source)
  10060   :error-patterns
  10061   ((error line-start
  10062           ;; llc prints the executable path
  10063           (zero-or-one (minimal-match (one-or-more not-newline)) ": ")
  10064           (file-name) ":" line ":" column ": error: " (message)
  10065           line-end))
  10066   :error-filter
  10067   (lambda (errors)
  10068     ;; sanitize errors occurring in inline assembly
  10069     (flycheck-sanitize-errors
  10070      (flycheck-remove-error-file-names "<inline asm>" errors)))
  10071   :modes llvm-mode)
  10072 
  10073 (flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc")
  10074 
  10075 (flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck
  10076   "The standards to use in luacheck.
  10077 
  10078 The value of this variable is either a list of strings denoting
  10079 the standards to use, or nil to pass nothing to luacheck.  When
  10080 non-nil, pass the standards via one or more `--std' options."
  10081   :type '(choice (const :tag "Default" nil)
  10082                  (repeat :tag "Custom standards"
  10083                          (string :tag "Standard name")))
  10084   :safe #'flycheck-string-list-p)
  10085 (make-variable-buffer-local 'flycheck-luacheck-standards)
  10086 
  10087 (flycheck-define-checker lua-luacheck
  10088   "A Lua syntax checker using luacheck.
  10089 
  10090 See URL `https://github.com/mpeterv/luacheck'."
  10091   :command ("luacheck"
  10092             "--formatter" "plain"
  10093             "--codes"                   ; Show warning codes
  10094             "--no-color"
  10095             (option-list "--std" flycheck-luacheck-standards)
  10096             (config-file "--config" flycheck-luacheckrc)
  10097             "--filename" source-original
  10098             ;; Read from standard input
  10099             "-")
  10100   :standard-input t
  10101   :error-patterns
  10102   ((warning line-start
  10103             (optional (file-name))
  10104             ":" line ":" column
  10105             ": (" (id "W" (one-or-more digit)) ") "
  10106             (message) line-end)
  10107    (error line-start
  10108           (optional (file-name))
  10109           ":" line ":" column ":"
  10110           ;; `luacheck' before 0.11.0 did not output codes for errors, hence
  10111           ;; the ID is optional here
  10112           (optional " (" (id "E" (one-or-more digit)) ") ")
  10113           (message) line-end))
  10114   :modes (lua-mode lua-ts-mode))
  10115 
  10116 (flycheck-define-checker lua
  10117   "A Lua syntax checker using the Lua compiler.
  10118 
  10119 See URL `https://www.lua.org/'."
  10120   :command ("luac" "-p" "-")
  10121   :standard-input t
  10122   :error-patterns
  10123   ((error line-start
  10124           ;; Skip the name of the luac executable.
  10125           (minimal-match (zero-or-more not-newline))
  10126           ": stdin:" line ": " (message) line-end))
  10127   :modes (lua-mode lua-ts-mode))
  10128 
  10129 (flycheck-define-checker opam
  10130   "A Opam syntax and style checker using opam lint.
  10131 
  10132 See URL `https://opam.ocaml.org/doc/man/opam-lint.html'."
  10133   :command ("opam" "lint" "-")
  10134   :standard-input t
  10135   :error-patterns
  10136   ((error line-start                    ; syntax error
  10137           (one-or-more space) "error  " (id ?2)
  10138           ": File format error"
  10139           (or (and " at line " line ", column " column ": " (message))
  10140               (and ": " (message)))
  10141           line-end)
  10142    (error line-start
  10143           (one-or-more space) "error  " (id ?3)
  10144           (minimal-match (zero-or-more not-newline))
  10145           "at line " line ", column " column ": " (message)
  10146           line-end)
  10147    (error line-start
  10148           (one-or-more space) "error " (id (one-or-more num))
  10149           ": " (message (one-or-more not-newline))
  10150           line-end)
  10151    (warning line-start
  10152             (one-or-more space) "warning " (id (one-or-more num))
  10153             ": " (message)
  10154             line-end))
  10155   :error-filter
  10156   (lambda (errors)
  10157     (flycheck-increment-error-columns
  10158      (flycheck-fill-empty-line-numbers errors)))
  10159   :modes tuareg-opam-mode)
  10160 
  10161 (flycheck-def-option-var flycheck-perl-include-path nil perl
  10162   "A list of include directories for Perl.
  10163 
  10164 The value of this variable is a list of strings, where each
  10165 string is a directory to add to the include path of Perl.
  10166 Relative paths are relative to the file being checked."
  10167   :type '(repeat (directory :tag "Include directory"))
  10168   :safe #'flycheck-string-list-p
  10169   :package-version '(flycheck . "0.24"))
  10170 
  10171 (flycheck-def-option-var flycheck-perl-module-list nil perl
  10172   "A list of modules to use for Perl.
  10173 
  10174 The value of this variable is a list of strings, where each
  10175 string is a module to `use' in Perl."
  10176   :type '(repeat :tag "Module")
  10177   :safe #'flycheck-string-list-p
  10178   :package-version '(flycheck . "32"))
  10179 
  10180 (flycheck-define-checker perl
  10181   "A Perl syntax checker using the Perl interpreter.
  10182 
  10183 See URL `https://www.perl.org'."
  10184   :command ("perl" "-w" "-c"
  10185             (option-list "-I" flycheck-perl-include-path)
  10186             (option-list "-M" flycheck-perl-module-list concat))
  10187   :standard-input t
  10188   :error-patterns
  10189   ((error line-start (minimal-match (message))
  10190           " at - line " line
  10191           (or "." (and ", " (zero-or-more not-newline))) line-end))
  10192   :modes (perl-mode cperl-mode)
  10193   :next-checkers (perl-perlcritic))
  10194 
  10195 (flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic
  10196   "The message severity for Perl Critic.
  10197 
  10198 The value of this variable is a severity level as integer, for
  10199 the `--severity' option to Perl Critic."
  10200   :type '(integer :tag "Severity level")
  10201   :safe #'integerp
  10202   :package-version '(flycheck . "0.18"))
  10203 
  10204 (flycheck-def-option-var flycheck-perlcritic-theme nil perl-perlcritic
  10205   "The theme expression for Perl Critic.
  10206 
  10207 The value of this variable is passed as the `--theme' option to
  10208 `Perl::Critic'.  See the documentation of `Perl::Critic' for
  10209 details."
  10210   :type '(choice (const :tag "None" nil)
  10211                  (string :tag "Theme expression"))
  10212   :safe #'flycheck-string-or-nil-p
  10213   :package-version '(flycheck . "32-csv"))
  10214 
  10215 (flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic
  10216                               ".perlcriticrc"
  10217   :package-version '(flycheck . "26"))
  10218 
  10219 (flycheck-define-checker perl-perlcritic
  10220   "A Perl syntax checker using Perl::Critic.
  10221 
  10222 See URL `https://metacpan.org/pod/Perl::Critic'."
  10223   :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n"
  10224             (config-file "--profile" flycheck-perlcriticrc)
  10225             (option "--severity" flycheck-perlcritic-severity nil
  10226                     flycheck-option-int)
  10227             (option "--theme" flycheck-perlcritic-theme))
  10228   :standard-input t
  10229   :error-patterns
  10230   ((info line-start
  10231          "STDIN/" line "/" column "/" (any "1") "/"
  10232          (id (one-or-more (not (any "/")))) "/" (message)
  10233          line-end)
  10234    (warning line-start
  10235             "STDIN/" line "/" column "/" (any "234") "/"
  10236             (id (one-or-more (not (any "/")))) "/" (message)
  10237             line-end)
  10238    (error line-start
  10239           "STDIN/" line "/" column "/" (any "5") "/"
  10240           (id (one-or-more (not (any "/")))) "/" (message)
  10241           line-end))
  10242   :modes (cperl-mode perl-mode)
  10243 
  10244   :error-explainer
  10245   (lambda (err)
  10246     (let ((error-code (flycheck-error-id err))
  10247           (url "https://metacpan.org/pod/Perl::Critic::Policy::%s"))
  10248       (and error-code `(url . ,(format url error-code))))))
  10249 
  10250 (flycheck-define-checker php
  10251   "A PHP syntax checker using the PHP command line interpreter.
  10252 
  10253 See URL `https://php.net/manual/en/features.commandline.php'."
  10254   :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
  10255             "-d" "log_errors=0" source)
  10256   :error-patterns
  10257   ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " "
  10258           (message) " in " (file-name) " on line " line line-end))
  10259   :modes (php-mode php-ts-mode php+-mode)
  10260   :next-checkers ((warning . php-phpmd)
  10261                   (warning . php-phpcs)))
  10262 
  10263 (flycheck-def-option-var flycheck-phpmd-rulesets
  10264     '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode")
  10265     php-phpmd
  10266   "The rule sets for PHP Mess Detector.
  10267 
  10268 Set default rule sets and custom rule set files.
  10269 
  10270 See section \"Using multiple rule sets\" in the PHP Mess Detector
  10271 manual at URL `https://phpmd.org/documentation/index.html'."
  10272   :type '(repeat :tag "rule sets"
  10273                  (string :tag "A filename or rule set"))
  10274   :safe #'flycheck-string-list-p)
  10275 
  10276 (flycheck-define-checker php-phpmd
  10277   "A PHP style checker using PHP Mess Detector.
  10278 
  10279 See URL `https://phpmd.org/'."
  10280   :command ("phpmd" source "xml"
  10281             (eval (flycheck-option-comma-separated-list
  10282                    flycheck-phpmd-rulesets)))
  10283   :error-parser flycheck-parse-phpmd
  10284   :modes (php-mode php-ts-mode php+-mode)
  10285   :next-checkers (php-phpcs))
  10286 
  10287 (flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs
  10288   "The coding standard for PHP CodeSniffer.
  10289 
  10290 When nil, use the default standard from the global PHP
  10291 CodeSniffer configuration.  When set to a string, pass the string
  10292 to PHP CodeSniffer which will interpret it as name as a standard,
  10293 or as path to a standard specification."
  10294   :type '(choice (const :tag "Default standard" nil)
  10295                  (string :tag "Standard name or file"))
  10296   :safe #'flycheck-string-or-nil-p)
  10297 
  10298 (flycheck-define-checker php-phpcs
  10299   "A PHP style checker using PHP Code Sniffer.
  10300 
  10301 Needs PHP Code Sniffer 2.6 or newer.
  10302 
  10303 See URL `https://pear.php.net/package/PHP_CodeSniffer/'."
  10304   :command ("phpcs" "--report=checkstyle"
  10305             ;; Use -q flag to force quiet mode
  10306             ;; Quiet mode prevents errors from extra output when phpcs has
  10307             ;; been configured with show_progress enabled
  10308             "-q"
  10309             (option "--standard=" flycheck-phpcs-standard concat)
  10310             ;; Some files are not detected correctly
  10311             ;; so it is necessary to pass the extension.
  10312             (eval
  10313              (when-let* ((fname buffer-file-name)
  10314                          (ext (file-name-extension fname)))
  10315                (concat "--extensions=" ext)))
  10316 
  10317             ;; Pass original file name to phpcs.  We need to concat explicitly
  10318             ;; here, because phpcs really insists to get option and argument as
  10319             ;; a single command line argument :|
  10320             (eval (when (buffer-file-name)
  10321                     (concat "--stdin-path=" (buffer-file-name))))
  10322             ;; Read from standard input
  10323             "-")
  10324   :standard-input t
  10325   :error-parser flycheck-parse-checkstyle
  10326   :error-filter
  10327   (lambda (errors)
  10328     (flycheck-sanitize-errors
  10329      (flycheck-remove-error-file-names "STDIN" errors)))
  10330   :modes (php-mode php-ts-mode php+-mode)
  10331   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
  10332   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
  10333   :predicate flycheck-buffer-nonempty-p)
  10334 
  10335 (flycheck-define-checker php-phpcs-changed
  10336   "A PHP style checker using PHPCS-Changed.
  10337    Needs PHP Code Sniffer 2.6 or newer.
  10338    See `https://github.com/sirbrillig/phpcs-changed'."
  10339   :command ("phpcs-changed"
  10340             "--git"
  10341             "--git-base trunk"
  10342             "--git-unstaged"
  10343             (option "--standard=" flycheck-phpcs-standard concat)
  10344             (eval (buffer-file-name))
  10345             )
  10346   :standard-input t
  10347   :error-parser flycheck-parse-checkstyle
  10348   :error-filter
  10349   (lambda (errors)
  10350     (flycheck-sanitize-errors
  10351      (flycheck-remove-error-file-names "STDIN" errors)))
  10352   :modes (php-mode php+-mode)
  10353   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
  10354   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
  10355   :predicate flycheck-buffer-nonempty-p)
  10356 
  10357 (flycheck-define-checker processing
  10358   "Processing command line tool.
  10359 
  10360 See https://github.com/processing/processing/wiki/Command-Line"
  10361   :command ("processing-java" "--force"
  10362             ;; Don't change the order of these arguments, processing is pretty
  10363             ;; picky
  10364             (eval (concat "--sketch=" (file-name-directory (buffer-file-name))))
  10365             (eval (concat "--output=" (flycheck-temp-dir-system)))
  10366             "--build")
  10367   :error-patterns
  10368   ((error line-start (file-name) ":" line ":" column
  10369           (zero-or-more (or digit ":")) (message) line-end))
  10370   :modes processing-mode
  10371   ;; This syntax checker needs a file name
  10372   :predicate (lambda () (buffer-file-name)))
  10373 
  10374 (defun flycheck-proselint-parse-errors (output checker buffer)
  10375   "Parse proselint json output errors from OUTPUT.
  10376 
  10377 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
  10378 the BUFFER that was checked respectively.
  10379 
  10380 See URL `https://proselint.com/' for more information about proselint."
  10381   (mapcar (lambda (err)
  10382             (let-alist err
  10383               (flycheck-error-new-at-pos
  10384                .start
  10385                (pcase .severity
  10386                  (`"suggestion" 'info)
  10387                  (`"warning"    'warning)
  10388                  (`"error"      'error)
  10389                  ;; Default to error
  10390                  (_             'error))
  10391                .message
  10392                :id .check
  10393                :buffer buffer
  10394                :checker checker
  10395                ;; See https://github.com/amperser/proselint/issues/1048
  10396                :end-pos .end)))
  10397           (let-alist (car (flycheck-parse-json output))
  10398             .data.errors)))
  10399 
  10400 (flycheck-define-checker proselint
  10401   "Flycheck checker using Proselint.
  10402 
  10403 See URL `https://proselint.com/'."
  10404   :command ("proselint" "--json" "-")
  10405   :standard-input t
  10406   :error-parser flycheck-proselint-parse-errors
  10407   :modes (text-mode markdown-mode gfm-mode message-mode org-mode))
  10408 
  10409 (flycheck-def-option-var flycheck-protoc-import-path nil protobuf-protoc
  10410   "A list of directories to resolve import directives.
  10411 
  10412 The value of this variable is a list of strings, where each
  10413 string is a directory to add to the import path.  Relative paths
  10414 are relative to the file being checked."
  10415   :type '(repeat (directory :tag "Import directory"))
  10416   :safe #'flycheck-string-list-p
  10417   :package-version '(flycheck . "32"))
  10418 
  10419 (flycheck-define-checker protobuf-protoc
  10420   "A protobuf syntax checker using the protoc compiler.
  10421 
  10422 See URL `https://developers.google.com/protocol-buffers/'."
  10423   :command ("protoc" "--error_format" "gcc"
  10424             (eval (concat "--java_out=" (flycheck-temp-dir-system)))
  10425             ;; Add the current directory to resolve imports
  10426             (eval (concat "--proto_path="
  10427                           (file-name-directory (buffer-file-name))))
  10428             ;; Add other import paths; this needs to be after the current
  10429             ;; directory to produce the right output.  See URL
  10430             ;; `https://github.com/flycheck/flycheck/pull/1655'
  10431             (option-list "--proto_path=" flycheck-protoc-import-path concat)
  10432             source-inplace)
  10433   :error-patterns
  10434   ((info line-start (file-name) ":" line ":" column
  10435          ": note: " (message) line-end)
  10436    (error line-start (file-name) ":" line ":" column
  10437           ": " (message) line-end)
  10438    (error line-start
  10439           (message "In file included from") " " (file-name) ":" line ":"
  10440           column ":" line-end))
  10441   :modes protobuf-mode
  10442   :predicate (lambda () (buffer-file-name)))
  10443 
  10444 (defun flycheck-prototool-project-root (&optional _checker)
  10445   "Return the nearest directory holding the prototool.yaml configuration."
  10446   (and buffer-file-name
  10447        (locate-dominating-file buffer-file-name "prototool.yaml")))
  10448 
  10449 (flycheck-define-checker protobuf-prototool
  10450   "A protobuf syntax checker using prototool.
  10451 
  10452 See URL `https://github.com/uber/prototool'."
  10453   :command ("prototool" "lint" source-original)
  10454   :error-patterns
  10455   ((warning line-start (file-name) ":" line ":" column ":" (message) line-end))
  10456   :modes protobuf-mode
  10457   :enabled flycheck-prototool-project-root
  10458   :predicate flycheck-buffer-saved-p)
  10459 
  10460 (flycheck-define-checker pug
  10461   "A Pug syntax checker using the pug compiler.
  10462 
  10463 See URL `https://pugjs.org/'."
  10464   :command ("pug" "-p" (eval (expand-file-name (buffer-file-name))))
  10465   :standard-input t
  10466   :error-patterns
  10467   ;; errors with includes/extends (e.g. missing files)
  10468   ((error "Error: " (message) (zero-or-more not-newline) "\n"
  10469           (zero-or-more not-newline) "at "
  10470           (zero-or-more not-newline) " line " line)
  10471    ;; error when placing anything other than a mixin or
  10472    ;; block at the top-level of an extended template
  10473    ;; also unknown filters
  10474    (error line-start "Error: " (file-name) ":"
  10475           line ":" column "\n\n" (message) line-end)
  10476    ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.)
  10477    (error line-start
  10478           (optional "Type") "Error: "  (file-name) ":"
  10479           line (optional ":" column)
  10480           (zero-or-more not-newline) "\n"
  10481           (one-or-more (or (zero-or-more not-newline) "|"
  10482                            (zero-or-more not-newline) "\n")
  10483                        (zero-or-more "-")  (zero-or-more not-newline) "|"
  10484                        (zero-or-more not-newline) "\n")
  10485           (zero-or-more not-newline) "\n"
  10486           (one-or-more
  10487            (zero-or-more not-newline) "|"
  10488            (zero-or-more not-newline) "\n")
  10489           (zero-or-more not-newline) "\n"
  10490           (message)
  10491           line-end))
  10492   :modes pug-mode)
  10493 
  10494 (flycheck-define-checker puppet-parser
  10495   "A Puppet DSL syntax checker using puppet's own parser.
  10496 
  10497 See URL `https://puppet.com/'."
  10498   :command ("puppet" "parser" "validate" "--color=false")
  10499   :standard-input t
  10500   :error-patterns
  10501   (
  10502    ;; Patterns for Puppet 4
  10503    (error line-start "Error: Could not parse for environment "
  10504           (one-or-more (in "a-z" "0-9" "_")) ":"
  10505           (message) "(line: " line ", column: " column ")" line-end)
  10506    ;; Errors from Puppet < 4
  10507    (error line-start "Error: Could not parse for environment "
  10508           (one-or-more (in "a-z" "0-9" "_")) ":"
  10509           (message (minimal-match (one-or-more anything)))
  10510           " at line " line line-end)
  10511    (error line-start
  10512           ;; Skip over the path of the Puppet executable
  10513           (minimal-match (zero-or-more not-newline))
  10514           ": Could not parse for environment " (one-or-more word)
  10515           ": " (message (minimal-match (zero-or-more anything)))
  10516           " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end))
  10517   :modes puppet-mode
  10518   :next-checkers ((warning . puppet-lint)))
  10519 
  10520 (flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint
  10521                               ".puppet-lint.rc"
  10522   :package-version '(flycheck . "26"))
  10523 
  10524 (flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint
  10525   "Disabled checkers for `puppet-lint'.
  10526 
  10527 The value of this variable is a list of strings, where each
  10528 string is the name of a check to disable (e.g. \"80chars\" or
  10529 \"double_quoted_strings\").
  10530 
  10531 See URL `https://puppet-lint.com/checks/' for a list of all checks
  10532 and their names."
  10533   :type '(repeat (string :tag "Check Name"))
  10534   :package-version '(flycheck . "26"))
  10535 
  10536 (defun flycheck-puppet-lint-disabled-arg-name (check)
  10537   "Create an argument to disable a puppetlint CHECK."
  10538   (concat "--no-" check "-check"))
  10539 
  10540 (flycheck-define-checker puppet-lint
  10541   "A Puppet DSL style checker using puppet-lint.
  10542 
  10543 See URL `https://puppet-lint.com/'."
  10544   ;; We must check the original file, because Puppetlint is quite picky on the
  10545   ;; names of files and there place in the directory structure, to comply with
  10546   ;; Puppet's autoload directory layout.  For instance, a class foo::bar is
  10547   ;; required to be in a file foo/bar.pp.  Any other place, such as a Flycheck
  10548   ;; temporary file will cause an error.
  10549   :command ("puppet-lint"
  10550             (config-file "--config" flycheck-puppet-lint-rc)
  10551             "--log-format"
  10552             "%{path}:%{line}:%{kind}: %{message} (%{check})"
  10553             (option-list "" flycheck-puppet-lint-disabled-checks concat
  10554                          flycheck-puppet-lint-disabled-arg-name)
  10555             source-original)
  10556   :error-patterns
  10557   ((warning line-start (file-name) ":" line ":warning: " (message) line-end)
  10558    (error line-start (file-name) ":" line ":error: " (message) line-end))
  10559   :modes puppet-mode
  10560   ;; Since we check the original file, we can only use this syntax checker if
  10561   ;; the buffer is actually linked to a file, and if it is not modified.
  10562   :predicate flycheck-buffer-saved-p)
  10563 
  10564 (defun flycheck-python-run-snippet (checker snippet)
  10565   "Run a python SNIPPET and return the output.
  10566 
  10567 CHECKER's executable is assumed to be a Python REPL."
  10568   (when-let (output (flycheck-call-checker-process-for-output
  10569                      checker nil nil "-c" snippet))
  10570     (string-trim output)))
  10571 
  10572 (defun flycheck-python-get-path (checker)
  10573   "Compute the current Python path (CHECKER is a Python REPL) ."
  10574   (flycheck-python-run-snippet checker "import sys; print(sys.path[1:])"))
  10575 
  10576 (defun flycheck-python-find-module (checker module)
  10577   "Check if a Python MODULE is available (CHECKER is a Python REPL)."
  10578   (flycheck-python-run-snippet
  10579    checker (concat "import sys; sys.path.pop(0);"
  10580                    (format "import %s; print(%s.__file__)" module module))))
  10581 
  10582 (defun flycheck-python-needs-module-p (checker)
  10583   "Determine whether CHECKER needs to be invoked through Python.
  10584 
  10585 Previous versions of Flycheck called pylint and flake8 directly,
  10586 while new version call them through `python -c'.  This check
  10587 ensures that we don't break existing code; it also allows people
  10588 who use virtualenvs to run globally-installed checkers."
  10589   (not (string-match-p (rx (or "pylint" "pylint3" "flake8")
  10590                            (or "-script.pyw" ".exe" ".bat" "")
  10591                            eos)
  10592                        (flycheck-checker-executable checker))))
  10593 
  10594 (defun flycheck-python-verify-module (checker module)
  10595   "Verify that a Python MODULE is available.
  10596 
  10597 Return nil if CHECKER's executable is not a Python REPL.  This
  10598 function's is suitable for a checker's :verify."
  10599   (when (flycheck-python-needs-module-p checker)
  10600     (let ((mod-path (flycheck-python-find-module checker module)))
  10601       (list (flycheck-verification-result-new
  10602              :label (format "`%s' module" module)
  10603              :message (if mod-path (format "Found at %S" mod-path)
  10604                         (format "Missing; sys.path is %s"
  10605                                 (flycheck-python-get-path checker)))
  10606              :face (if mod-path 'success '(bold error)))))))
  10607 
  10608 (defun flycheck-python-module-args (checker module-name)
  10609   "Compute arguments to pass to CHECKER's executable to run MODULE-NAME.
  10610 
  10611 Return nil if CHECKER's executable is not a Python REPL.
  10612 Otherwise, return a list starting with -c (-m is not enough
  10613 because it adds the current directory to Python's path)."
  10614   (when (flycheck-python-needs-module-p checker)
  10615     `("-c" ,(concat "import sys;sys.path.pop(0);import runpy;"
  10616                     (format "runpy.run_module(%S, run_name='__main__')" module-name )))))
  10617 
  10618 (defcustom flycheck-python-project-files
  10619   '("pyproject.toml" "setup.cfg" "mypy.ini" "pyrightconfig.json")
  10620   "Files used to find where to run Python checkers from.
  10621 Currently used for pylint, flake8, and pyright.
  10622 
  10623 The presence of one in these files indicates the root of the
  10624 current project; `.pylintrc' is not part of the list because it
  10625 is commonly found in ~/."
  10626   :group 'flycheck
  10627   :type '(repeat (string :tag "File name"))
  10628   :package-version '(flycheck . "33")
  10629   :safe #'flycheck-string-list-p)
  10630 
  10631 (defun flycheck-python-find-project-root (_checker)
  10632   "Find the root directory of a Python project.
  10633 
  10634 The root directory is assumed to be the nearest parent directory
  10635 that contains one of `flycheck-python-project-files'.  If no such
  10636 file is found, we use the same heuristic as epylint: the nearest
  10637 parent directory that doesn't have a __init__.py file."
  10638   (let ((start (if buffer-file-name
  10639                    (file-name-directory buffer-file-name)
  10640                  default-directory)))
  10641     (or (flycheck--locate-dominating-file-matching
  10642          start (regexp-opt flycheck-python-project-files))
  10643         (locate-dominating-file
  10644          start (lambda (dir)
  10645                  (not (file-exists-p (expand-file-name "__init__.py" dir))))))))
  10646 
  10647 (flycheck-def-config-file-var flycheck-flake8rc python-flake8
  10648                               '(".flake8" "setup.cfg" "tox.ini"))
  10649 
  10650 (flycheck-def-option-var flycheck-flake8-error-level-alist
  10651     '(("^E9.*$"  . error)               ; Syntax errors from pep8
  10652       ("^F82.*$" . error)               ; undefined variables from pyflakes
  10653       ("^F83.*$" . error)               ; Duplicate arguments from flake8
  10654       ("^D.*$"   . info)                ; Docstring issues from flake8-pep257
  10655       ("^N.*$"   . info)                ; Naming issues from pep8-naming
  10656       )
  10657     python-flake8
  10658   "An alist mapping flake8 error IDs to Flycheck error levels.
  10659 
  10660 Each item in this list is a cons cell `(PATTERN . LEVEL)' where
  10661 PATTERN is a regular expression matched against the error ID, and
  10662 LEVEL is a Flycheck error level symbol.
  10663 
  10664 Each PATTERN is matched in the order of appearance in this list
  10665 against the error ID.  If it matches the ID, the level of the
  10666 corresponding error is set to LEVEL.  An error that is not
  10667 matched by any PATTERN defaults to warning level.
  10668 
  10669 The default value of this option matches errors from flake8
  10670 itself and from the following flake8 plugins:
  10671 
  10672 - pep8-naming
  10673 - flake8-pep257
  10674 
  10675 You may add your own mappings to this option in order to support
  10676 further flake8 plugins."
  10677   :type '(repeat (cons (regexp :tag "Error ID pattern")
  10678                        (symbol :tag "Error level")))
  10679   :package-version '(flycheck . "0.22"))
  10680 
  10681 (flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8
  10682   "The maximum McCabe complexity of methods.
  10683 
  10684 If nil, do not check the complexity of methods.  If set to an
  10685 integer, report any complexity greater than the value of this
  10686 variable as warning.
  10687 
  10688 If set to an integer, this variable overrules any similar setting
  10689 in the configuration file denoted by `flycheck-flake8rc'."
  10690   :type '(choice (const :tag "Do not check McCabe complexity" nil)
  10691                  (integer :tag "Maximum complexity"))
  10692   :safe #'integerp)
  10693 
  10694 (flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8
  10695   "The maximum length of lines.
  10696 
  10697 If set to an integer, the value of this variable denotes the
  10698 maximum length of lines, overruling any similar setting in the
  10699 configuration file denoted by `flycheck-flake8rc'.  An error will
  10700 be reported for any line longer than the value of this variable.
  10701 
  10702 If set to nil, use the maximum line length from the configuration
  10703 file denoted by `flycheck-flake8rc', or the PEP 8 recommendation
  10704 of 79 characters if there is no configuration with this setting."
  10705   :type '(choice (const :tag "Default value")
  10706                  (integer :tag "Maximum line length in characters"))
  10707   :safe #'integerp)
  10708 
  10709 (defun flycheck-flake8-fix-error-level (err)
  10710   "Fix the error level of ERR.
  10711 
  10712 Update the error level of ERR according to
  10713 `flycheck-flake8-error-level-alist'."
  10714   (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist)
  10715     (when (string-match-p pattern (flycheck-error-id err))
  10716       (setf (flycheck-error-level err) level)))
  10717   err)
  10718 
  10719 (defun flycheck-flake8--find-project-root (_checker)
  10720   "Find setup.cfg in a parent directory of the current buffer."
  10721   ;; This is a workaround for `https://gitlab.com/pycqa/flake8/issues/517'; see
  10722   ;; also `https://github.com/flycheck/flycheck/issues/1722'
  10723   (locate-dominating-file (or buffer-file-name default-directory) "setup.cfg"))
  10724 
  10725 (flycheck-define-checker python-flake8
  10726   "A Python syntax and style checker using Flake8.
  10727 
  10728 Requires Flake8 3.0 or newer. See URL
  10729 `https://flake8.readthedocs.io/'."
  10730   ;; Not calling flake8 directly makes it easier to switch between different
  10731   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
  10732   :command ("python3"
  10733             (eval (flycheck-python-module-args 'python-flake8 "flake8"))
  10734             "--format=default"
  10735             (config-file "--append-config" flycheck-flake8rc)
  10736             (option "--max-complexity" flycheck-flake8-maximum-complexity nil
  10737                     flycheck-option-int)
  10738             (option "--max-line-length" flycheck-flake8-maximum-line-length nil
  10739                     flycheck-option-int)
  10740             (eval (when buffer-file-name
  10741                     (concat "--stdin-display-name=" buffer-file-name)))
  10742             "-")
  10743   :standard-input t
  10744   :working-directory flycheck-python-find-project-root
  10745   :error-filter (lambda (errors)
  10746                   (let ((errors (flycheck-sanitize-errors errors)))
  10747                     (seq-map #'flycheck-flake8-fix-error-level errors)))
  10748   :error-patterns
  10749   ((warning line-start
  10750             (file-name) ":" line ":" (optional column ":") " "
  10751             (id (one-or-more (any alpha)) (one-or-more digit)) " "
  10752             (message (one-or-more not-newline))
  10753             line-end))
  10754   :enabled (lambda ()
  10755              (or (not (flycheck-python-needs-module-p 'python-flake8))
  10756                  (flycheck-python-find-module 'python-flake8 "flake8")))
  10757   :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8"))
  10758   :modes (python-mode python-ts-mode)
  10759   :next-checkers ((warning . python-pylint)
  10760                   (warning . python-mypy)))
  10761 
  10762 (flycheck-def-config-file-var flycheck-python-ruff-config python-ruff
  10763                               '("pyproject.toml" "ruff.toml" ".ruff.toml"))
  10764 
  10765 (flycheck-define-checker python-ruff
  10766   "A Python syntax and style checker using the ruff.
  10767 To override the path to the ruff executable, set
  10768 `flycheck-python-ruff-executable'.
  10769 
  10770 See URL `https://beta.ruff.rs/docs/'."
  10771   :command ("ruff"
  10772             "check"
  10773             (config-file "--config" flycheck-python-ruff-config)
  10774             "--output-format=text"
  10775             "--stdin-filename" source-original
  10776             "-")
  10777   :standard-input t
  10778   :error-filter (lambda (errors)
  10779                   (let ((errors (flycheck-sanitize-errors errors)))
  10780                     (seq-map #'flycheck-flake8-fix-error-level errors)))
  10781   :error-patterns
  10782   ((warning line-start
  10783             (file-name) ":" line ":" (optional column ":") " "
  10784             (id (one-or-more (any alpha)) (one-or-more digit)) " "
  10785             (message (one-or-more not-newline))
  10786             line-end))
  10787   :modes (python-mode python-ts-mode)
  10788   :next-checkers ((warning . python-mypy)))
  10789 
  10790 (flycheck-def-config-file-var
  10791     flycheck-pylintrc python-pylint
  10792     '("pylintrc" ".pylintrc" "pyproject.toml" "setup.cfg"))
  10793 
  10794 (flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint
  10795   "Whether to use pylint message symbols or message codes.
  10796 
  10797 A pylint message has both an opaque identifying code (such as `F0401') and a
  10798 more meaningful symbolic code (such as `import-error').  This option governs
  10799 which should be used and reported to the user."
  10800   :type 'boolean
  10801   :safe #'booleanp
  10802   :package-version '(flycheck . "0.25"))
  10803 
  10804 (defun flycheck-parse-pylint (output checker buffer)
  10805   "Parse JSON OUTPUT of CHECKER on BUFFER as Pylint errors."
  10806   (mapcar (lambda (err)
  10807             (let-alist err
  10808               ;; Pylint can return -1 as a line or a column, hence the call to
  10809               ;; `max'.  See `https://github.com/flycheck/flycheck/issues/1383'.
  10810               (flycheck-error-new-at
  10811                (and .line (max .line 1))
  10812                (and .column (max (1+ .column) 1))
  10813                (pcase .type
  10814                  ;; See "pylint/utils.py"
  10815                  ((or "fatal" "error") 'error)
  10816                  ((or "info" "convention") 'info)
  10817                  ((or "warning" "refactor" _) 'warning))
  10818                ;; Drop lines showing the error in context
  10819                (and (string-match (rx (*? nonl) eol) .message)
  10820                     (match-string 0 .message))
  10821                :id (if flycheck-pylint-use-symbolic-id .symbol .message-id)
  10822                :checker checker
  10823                :buffer buffer
  10824                :filename .path)))
  10825           (car (flycheck-parse-json output))))
  10826 
  10827 (flycheck-define-checker python-pylint
  10828   "A Python syntax and style checker using Pylint.
  10829 
  10830 This syntax checker requires Pylint 1.0 or newer.
  10831 
  10832 See URL `https://www.pylint.org/'."
  10833   ;; --reports=n disables the scoring report.
  10834   ;; Not calling pylint directly makes it easier to switch between different
  10835   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
  10836   :command ("python3"
  10837             (eval (flycheck-python-module-args 'python-pylint "pylint"))
  10838             "--reports=n"
  10839             "--output-format=json"
  10840             (config-file "--rcfile=" flycheck-pylintrc concat)
  10841             ;; Need `source-inplace' for relative imports (e.g. `from .foo
  10842             ;; import bar'), see https://github.com/flycheck/flycheck/issues/280
  10843             source-inplace)
  10844   :error-parser flycheck-parse-pylint
  10845   :working-directory flycheck-python-find-project-root
  10846   :enabled (lambda ()
  10847              (or (not (flycheck-python-needs-module-p 'python-pylint))
  10848                  (flycheck-python-find-module 'python-pylint "pylint")))
  10849   :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint"))
  10850   :error-explainer (lambda (err)
  10851                      (when-let (id (flycheck-error-id err))
  10852                        (apply
  10853                         #'flycheck-call-checker-process-for-output
  10854                         'python-pylint nil t
  10855                         (append
  10856                          (flycheck-python-module-args 'python-pylint "pylint")
  10857                          (list (format "--help-msg=%s" id))))))
  10858   :modes (python-mode python-ts-mode)
  10859   :next-checkers ((warning . python-mypy)))
  10860 
  10861 (flycheck-define-checker python-pycompile
  10862   "A Python syntax checker using Python's builtin compiler.
  10863 
  10864 See URL `https://docs.python.org/3.4/library/py_compile.html'."
  10865   :command ("python3" "-m" "py_compile" source)
  10866   :error-patterns
  10867   ;; Python 2.7
  10868   ((error line-start "  File \"" (file-name) "\", line " line "\n"
  10869           (>= 2 (zero-or-more not-newline) "\n")
  10870           "SyntaxError: " (message) line-end)
  10871    (error line-start "Sorry: IndentationError: "
  10872           (message) "(" (file-name) ", line " line ")"
  10873           line-end)
  10874    ;; 2.6
  10875    (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'"))))
  10876           "', ('" (file-name (one-or-more (not (any "'")))) "', "
  10877           line ", " column ", " (one-or-more not-newline) line-end))
  10878   :working-directory flycheck-python-find-project-root
  10879   :modes (python-mode python-ts-mode)
  10880   :next-checkers ((warning . python-mypy)))
  10881 
  10882 (defun flycheck-pyright--parse-error (output checker buffer)
  10883   "Parse pyright errors/warnings from JSON OUTPUT.
  10884 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  10885 the BUFFER that was checked respectively."
  10886   (seq-map
  10887    (lambda (err)
  10888      (let-alist err
  10889        (flycheck-error-new-at
  10890         (+ 1 .range.start.line)
  10891         (+ 1 .range.start.character)
  10892         (pcase .severity
  10893           ("error" 'error)
  10894           ("warning" 'warning)
  10895           (_ 'warning))
  10896         .message
  10897         :end-line (+ 1 .range.end.line)
  10898         :end-column (+ 1 .range.end.character)
  10899         :checker checker
  10900         :buffer buffer
  10901         :filename (buffer-file-name buffer))))
  10902    (cdr (nth 2 (car (flycheck-parse-json output))))))
  10903 
  10904 (flycheck-define-checker python-pyright
  10905   "Static type checker for Python
  10906 
  10907 See URL https://github.com/microsoft/pyright."
  10908   :command ("pyright"
  10909             "--outputjson"
  10910             source-inplace)
  10911   :working-directory flycheck-python-find-project-root
  10912   :error-parser flycheck-pyright--parse-error
  10913   :modes (python-mode python-ts-mode))
  10914 
  10915 (define-obsolete-variable-alias 'flycheck-python-mypy-ini
  10916   'flycheck-python-mypy-config "32")
  10917 
  10918 (flycheck-def-config-file-var flycheck-python-mypy-config python-mypy
  10919                               '("mypy.ini" "pyproject.toml" "setup.cfg"))
  10920 
  10921 (flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy
  10922   "Directory used to write .mypy_cache directories."
  10923   :type '(choice
  10924           (const :tag "Write to the working directory" nil)
  10925           (const :tag "Never write .mypy_cache directories" null-device)
  10926           (string :tag "Path"))
  10927   :safe #'flycheck-string-or-nil-p
  10928   :package-version '(flycheck . "32"))
  10929 
  10930 (flycheck-def-option-var flycheck-python-mypy-python-executable nil python-mypy
  10931   "Python executable to find the installed PEP 561 packages."
  10932   :type '(choice (const :tag "Same as mypy's" nil)
  10933                  (string :tag "Path"))
  10934   :safe #'flycheck-string-or-nil-p
  10935   :package-version '(flycheck . "33"))
  10936 
  10937 (flycheck-define-checker python-mypy
  10938   "Mypy syntax and type checker.  Requires mypy>=0.730.
  10939 
  10940 See URL `https://mypy-lang.org/'."
  10941   :command ("mypy"
  10942             "--show-column-numbers"
  10943             "--no-pretty"
  10944             (config-file "--config-file" flycheck-python-mypy-config)
  10945             (option "--cache-dir" flycheck-python-mypy-cache-dir)
  10946             (option "--python-executable" flycheck-python-mypy-python-executable)
  10947             source-original)
  10948   :error-patterns
  10949   ((error line-start (file-name) ":" line (optional ":" column)
  10950           ": error:" (message) line-end)
  10951    (warning line-start (file-name) ":" line (optional ":" column)
  10952             ": warning:" (message) line-end)
  10953    (info line-start (file-name) ":" line (optional ":" column)
  10954          ": note:" (message) line-end))
  10955   :working-directory flycheck-python-find-project-root
  10956   :modes (python-mode python-ts-mode)
  10957   ;; Ensure the file is saved, to work around
  10958   ;; https://github.com/python/mypy/issues/4746.
  10959   :predicate flycheck-buffer-saved-p)
  10960 
  10961 (flycheck-def-option-var flycheck-lintr-caching t r-lintr
  10962   "Whether to enable caching in lintr.
  10963 
  10964 By default, lintr caches all expressions in a file and re-checks
  10965 only those that have changed.  Setting this option to nil
  10966 disables caching in case there are problems."
  10967   :type 'boolean
  10968   :safe #'booleanp
  10969   :package-version '(flycheck . "0.23"))
  10970 
  10971 (flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr
  10972   "Linters to use with lintr.
  10973 
  10974 The value of this variable is a string containing an R
  10975 expression, which selects linters for lintr."
  10976   :type 'string
  10977   :risky t
  10978   :package-version '(flycheck . "0.23"))
  10979 
  10980 (defun flycheck-r-has-lintr (checker)
  10981   "Whether CHECKER (R) has installed the `lintr' library."
  10982   (eql 0 (flycheck-call-checker-process
  10983           checker nil nil nil
  10984           "--slave" "--no-restore" "--no-save" "-e"
  10985           "library('lintr')")))
  10986 
  10987 (flycheck-define-checker r-lintr
  10988   "An R style and syntax checker using the lintr package.
  10989 
  10990 See URL `https://github.com/jimhester/lintr'."
  10991   :command ("R" "--slave" "--no-restore" "--no-save" "-e"
  10992             (eval (concat
  10993                    "library(lintr);"
  10994                    "try(lint(commandArgs(TRUE)"
  10995                    ", cache=" (if flycheck-lintr-caching "TRUE" "FALSE")
  10996                    ", " flycheck-lintr-linters
  10997                    "))"))
  10998             "--args" source)
  10999   :error-patterns
  11000   ((info line-start (file-name) ":" line ":" column ": style: " (message)
  11001          line-end)
  11002    (warning line-start (file-name) ":" line ":" column ": warning: " (message)
  11003             line-end)
  11004    (error line-start (file-name) ":" line ":" column ": error: " (message)
  11005           line-end))
  11006   :modes (ess-mode ess-r-mode)
  11007   :predicate
  11008   ;; Don't check ESS files which do not contain R, and make sure that lintr is
  11009   ;; actually available
  11010   (lambda ()
  11011     (and (equal ess-language "S")
  11012          (flycheck-r-has-lintr 'r-lintr)))
  11013   :verify (lambda (checker)
  11014             (let ((has-lintr (flycheck-r-has-lintr checker)))
  11015               (list
  11016                (flycheck-verification-result-new
  11017                 :label "lintr library"
  11018                 :message (if has-lintr "present" "missing")
  11019                 :face (if has-lintr 'success '(bold error)))))))
  11020 
  11021 (flycheck-define-checker r
  11022   "An R syntax checker using the builtin `parse' function.
  11023 
  11024 See URL: `https://www.r-project.org/'."
  11025   :command ("R" "--slave" "--no-restore" "--no-save" "-e"
  11026             "parse(file=file('stdin'), srcfile='<stdin>')")
  11027   :standard-input t
  11028   :error-patterns
  11029   ((error line-start (zero-or-more space) "<stdin>:" line ":" column ": "
  11030           (message) line-end))
  11031   :modes (ess-mode ess-r-mode)
  11032   :predicate
  11033   ;; Don't check ESS files which do not contain R
  11034   (lambda () (equal ess-language "S")))
  11035 
  11036 (defun flycheck-racket-has-expand-p (checker)
  11037   "Whether the executable of CHECKER provides the `expand' command."
  11038   (eql 0 (flycheck-call-checker-process checker nil nil nil "expand")))
  11039 
  11040 (flycheck-define-checker racket
  11041   "A Racket syntax checker with `raco expand'.
  11042 
  11043 The `compiler-lib' racket package is required for this syntax
  11044 checker.
  11045 
  11046 See URL `https://racket-lang.org/'."
  11047   :command ("raco" "expand" source-inplace)
  11048   :predicate
  11049   (lambda ()
  11050     (and (or (not (eq major-mode 'scheme-mode))
  11051              ;; In `scheme-mode' we must check the current Scheme implementation
  11052              ;; being used
  11053              (and (boundp 'geiser-impl--implementation)
  11054                   (eq geiser-impl--implementation 'racket)))
  11055          (flycheck-racket-has-expand-p 'racket)))
  11056   :verify
  11057   (lambda (checker)
  11058     (let ((has-expand (flycheck-racket-has-expand-p checker))
  11059           (in-scheme-mode (eq major-mode 'scheme-mode))
  11060           (geiser-impl (bound-and-true-p geiser-impl--implementation)))
  11061       (list
  11062        (flycheck-verification-result-new
  11063         :label "compiler-lib package"
  11064         :message (if has-expand "present" "missing")
  11065         :face (if has-expand 'success '(bold error)))
  11066        (flycheck-verification-result-new
  11067         :label "Geiser Implementation"
  11068         :message (cond
  11069                   ((not in-scheme-mode) "Using Racket Mode")
  11070                   ((eq geiser-impl 'racket) "Racket")
  11071                   (geiser-impl (format "Other: %s" geiser-impl))
  11072                   (t "Geiser not active"))
  11073         :face (cond
  11074                ((or (not in-scheme-mode) (eq geiser-impl 'racket)) 'success)
  11075                (t '(bold error)))))))
  11076   :error-filter
  11077   (lambda (errors)
  11078     (flycheck-sanitize-errors
  11079      (flycheck-increment-error-columns
  11080       (seq-remove
  11081        (lambda (err)
  11082          (string-suffix-p
  11083           "/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt"
  11084           (flycheck-error-filename err)))
  11085        errors))))
  11086   :error-patterns
  11087   ((error line-start (zero-or-more space)
  11088           (file-name) ":" line ":" column ":" (message) line-end))
  11089   :modes (racket-mode scheme-mode))
  11090 
  11091 (flycheck-define-checker rpm-rpmlint
  11092   "A RPM SPEC file syntax checker using rpmlint.
  11093 
  11094 See URL `https://github.com/rpm-software-management/rpmlint'."
  11095   :command ("rpmlint" source)
  11096   :error-patterns
  11097   ((error line-start
  11098           (file-name) ":" (optional line ":") " E: " (message)
  11099           line-end)
  11100    (warning line-start
  11101             (file-name) ":" (optional line ":") " W: " (message)
  11102             line-end))
  11103   :error-filter
  11104   ;; rpmlint 1.1 outputs a spurious error for the temp file created by flycheck
  11105   (lambda (errors)
  11106     (dolist (err (seq-remove
  11107                   (lambda (err)
  11108                     (string-suffix-p "(none)" (flycheck-error-filename err)))
  11109                   errors))
  11110       ;; Add fake line numbers if they are missing in the lint output
  11111       (unless (flycheck-error-line err)
  11112         (setf (flycheck-error-line err) 1)))
  11113     errors)
  11114   :error-explainer
  11115   (lambda (error)
  11116     (when-let* ((error-message (flycheck-error-message error))
  11117                 (message-id (save-match-data
  11118                               (string-match "\\([^ ]+\\)" error-message)
  11119                               (match-string 1 error-message))))
  11120       (flycheck-call-checker-process-for-output
  11121        'rpm-rpmlint nil t "-I" message-id)))
  11122   :modes (sh-mode rpm-spec-mode)
  11123   :predicate (lambda () (or (not (eq major-mode 'sh-mode))
  11124                             ;; In `sh-mode', we need the proper shell
  11125                             (eq sh-shell 'rpm))))
  11126 
  11127 (flycheck-def-config-file-var flycheck-markdown-markdownlint-cli-config
  11128     markdown-markdownlint-cli
  11129     '(".markdownlint.json" ".markdownlint.jsonc" ".markdownlint.yaml")
  11130   :package-version '(flycheck . "33"))
  11131 
  11132 (flycheck-def-option-var flycheck-markdown-markdownlint-cli-disable-rules
  11133     nil markdown-markdownlint-cli
  11134   "Rules to disable for markdownlint-cli."
  11135   :type '(repeat :tag "Disabled rule"
  11136                  (string :tag "Rule name"))
  11137   :safe #'flycheck-string-list-p
  11138   :package-version '(flycheck . "33"))
  11139 
  11140 (flycheck-def-option-var flycheck-markdown-markdownlint-cli-enable-rules
  11141     nil markdown-markdownlint-cli
  11142   "Rules to enable for markdownlint-cli."
  11143   :type '(repeat :tag "Enabled rule"
  11144                  (string :tag "Rule name"))
  11145   :safe #'flycheck-string-list-p
  11146   :package-version '(flycheck . "33"))
  11147 
  11148 (flycheck-define-checker markdown-markdownlint-cli
  11149   "Markdown checker using markdownlint-cli.
  11150 
  11151 See URL `https://github.com/igorshubovych/markdownlint-cli'."
  11152   :command ("markdownlint"
  11153             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
  11154             (option-list "--disable" flycheck-markdown-markdownlint-cli-disable-rules)
  11155             (option-list "--enable" flycheck-markdown-markdownlint-cli-enable-rules)
  11156             "--"
  11157             source)
  11158   :error-patterns
  11159   ((error line-start
  11160           (file-name) ":" line
  11161           (? ":" column) " " (id (one-or-more (not (any space))))
  11162           " " (message) line-end))
  11163   :error-filter
  11164   (lambda (errors)
  11165     (flycheck-sanitize-errors
  11166      (flycheck-remove-error-file-names "(string)" errors)))
  11167   :modes (markdown-mode gfm-mode)
  11168   :error-explainer
  11169   (lambda (err)
  11170     (let ((error-code (substring (flycheck-error-id err) 0 5))
  11171           (url "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#%s"))
  11172       (and error-code `(url . ,(format url error-code))))))
  11173 
  11174 (flycheck-def-option-var flycheck-markdown-mdl-rules nil markdown-mdl
  11175   "Rules to enable for mdl.
  11176 
  11177 The value of this variable is a list of strings each of which is
  11178 the name of a rule to enable.
  11179 
  11180 By default all rules are enabled.
  11181 
  11182 See URL `https://git.io/vhi2t'."
  11183   :type '(repeat :tag "Enabled rules"
  11184                  (string :tag "rule name"))
  11185   :safe #'flycheck-string-list-p
  11186   :package-version '(flycheck . "27"))
  11187 
  11188 (flycheck-def-option-var flycheck-markdown-mdl-tags nil markdown-mdl
  11189   "Rule tags to enable for mdl.
  11190 
  11191 The value of this variable is a list of strings each of which is
  11192 the name of a rule tag.  Only rules with these tags are enabled.
  11193 
  11194 By default all rules are enabled.
  11195 
  11196 See URL `https://git.io/vhi2t'."
  11197   :type '(repeat :tag "Enabled tags"
  11198                  (string :tag "tag name"))
  11199   :safe #'flycheck-string-list-p
  11200   :package-version '(flycheck . "27"))
  11201 
  11202 (flycheck-def-config-file-var flycheck-markdown-mdl-style markdown-mdl nil
  11203   :package-version '(flycheck . "27"))
  11204 
  11205 (flycheck-define-checker markdown-mdl
  11206   "Markdown checker using mdl.
  11207 
  11208 See URL `https://github.com/markdownlint/markdownlint'."
  11209   :command ("mdl"
  11210             (config-file "--style" flycheck-markdown-mdl-style)
  11211             (option "--tags=" flycheck-markdown-mdl-tags concat
  11212                     flycheck-option-comma-separated-list)
  11213             (option "--rules=" flycheck-markdown-mdl-rules concat
  11214                     flycheck-option-comma-separated-list))
  11215   :standard-input t
  11216   :error-patterns
  11217   ((error line-start
  11218           (file-name) ":" line ": " (id (one-or-more alnum)) " " (message)
  11219           line-end))
  11220   :error-filter
  11221   (lambda (errors)
  11222     (flycheck-sanitize-errors
  11223      (flycheck-remove-error-file-names "(stdin)" errors)))
  11224   :modes (markdown-mode gfm-mode))
  11225 
  11226 (flycheck-def-config-file-var flycheck-markdown-pymarkdown-config
  11227     markdown-pymarkdown nil
  11228   :package-version '(flycheck . "34"))
  11229 
  11230 (flycheck-define-checker markdown-pymarkdown
  11231   "Markdown checker using PyMarkdown.
  11232 
  11233 See URL `https://pypi.org/project/pymarkdownlnt/'."
  11234   :command ("pymarkdown"
  11235             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
  11236             "scan"
  11237             source)
  11238   :error-patterns
  11239   ((error line-start
  11240           (file-name) ":" line
  11241           (? ":" column) ": " (id (one-or-more alnum))
  11242           ": " (message) line-end))
  11243   :error-filter
  11244   (lambda (errors)
  11245     (flycheck-sanitize-errors
  11246      (flycheck-remove-error-file-names "(string)" errors)))
  11247   :modes (markdown-mode gfm-mode))
  11248 
  11249 (flycheck-define-checker nix
  11250   "Nix checker using nix-instantiate.
  11251 
  11252 See URL `https://nixos.org/nix/manual/#sec-nix-instantiate'."
  11253   :command ("nix-instantiate" "--parse" "-")
  11254   :standard-input t
  11255   :error-patterns
  11256   ((error line-start
  11257           "error: " (message)
  11258           (one-or-more "\n")
  11259           (zero-or-more space) "at «stdin»:" line ":" column ":" line-end)
  11260    (error line-start
  11261           "at: (" line ":" column ") from stdin"
  11262           (one-or-more "\n" (zero-or-more space (one-or-more not-newline)))
  11263           (message) line-end)
  11264    (error line-start
  11265           "error: " (message) " at " (file-name) ":" line ":" column
  11266           line-end))
  11267   :error-filter
  11268   (lambda (errors)
  11269     (flycheck-sanitize-errors
  11270      (flycheck-remove-error-file-names "(string)" errors)))
  11271   :next-checkers ((warning . nix-linter))
  11272   :modes (nix-mode nix-ts-mode))
  11273 
  11274 (defun flycheck-parse-nix-linter (output checker buffer)
  11275   "Parse nix-linter warnings from JSON OUTPUT.
  11276 
  11277 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  11278 the BUFFER that was checked respectively.
  11279 
  11280 See URL `https://github.com/Synthetica9/nix-linter' for more
  11281 information about nix-linter."
  11282   (mapcar (lambda (err)
  11283             (let-alist err
  11284               (flycheck-error-new-at
  11285                .pos.spanBegin.sourceLine
  11286                .pos.spanBegin.sourceColumn
  11287                'warning
  11288                .description
  11289                :id .offense
  11290                :checker checker
  11291                :buffer buffer
  11292                :filename (buffer-file-name buffer)
  11293                :end-line .pos.spanEnd.sourceLine
  11294                :end-column .pos.spanEnd.sourceColumn)))
  11295           (flycheck-parse-json output)))
  11296 
  11297 (flycheck-define-checker nix-linter
  11298   "Nix checker using nix-linter.
  11299 
  11300 See URL `https://github.com/Synthetica9/nix-linter'."
  11301   :command ("nix-linter" "--json-stream" "-")
  11302   :standard-input t
  11303   :error-parser flycheck-parse-nix-linter
  11304   :error-explainer
  11305   (lambda (error)
  11306     (when-let (error-code (flycheck-error-id error))
  11307       (flycheck-call-checker-process-for-output
  11308        'nix-linter nil t "--help-for" error-code)))
  11309   :modes (nix-mode nix-ts-mode))
  11310 
  11311 (defun flycheck-parse-statix (output checker buffer)
  11312   "Parse statix warnings from JSON OUTPUT.
  11313 
  11314 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  11315 the BUFFER that was checked respectively.
  11316 
  11317 See URL `https://github.com/nerdypepper/statix' for more
  11318 information about statix."
  11319   (mapcar (lambda (err)
  11320             ;; Diagnostic information is a (seemingly always) 1 element array.
  11321             (let-alist (car (alist-get 'diagnostics err))
  11322               (let ((message .message)
  11323                     (start-line .at.from.line)
  11324                     (start-column .at.from.column)
  11325                     (end-line .at.to.line)
  11326                     (end-column .at.to.column))
  11327 
  11328                 (let-alist err
  11329                   (flycheck-error-new-at
  11330                    start-line
  11331                    start-column
  11332                    (pcase .severity ("Error" 'error)
  11333                           ("Warn" 'warning)
  11334                           (_ 'warning))
  11335                    (format "%s: %s" .note message)
  11336                    :id (format "%s%02d" (pcase .severity
  11337                                           ("Error" "E")
  11338                                           ("Warn" "W")
  11339                                           (_ "")) .code)
  11340                    :checker checker
  11341                    :buffer buffer
  11342                    :filename (buffer-file-name buffer)
  11343                    :end-line end-line
  11344                    :end-column end-column)))))
  11345           (alist-get 'report (car (flycheck-parse-json output)))))
  11346 
  11347 (flycheck-define-checker statix
  11348   "Nix checker using statix.
  11349 
  11350 See URL `https://github.com/nerdypepper/statix'."
  11351   :command ("statix" "check" "-o=json" source)
  11352   :error-parser flycheck-parse-statix
  11353   :modes nix-mode)
  11354 
  11355 (defun flycheck-locate-sphinx-source-directory ()
  11356   "Locate the Sphinx source directory for the current buffer.
  11357 
  11358 Return the source directory, or nil, if the current buffer is not
  11359 part of a Sphinx project."
  11360   (when-let* ((filename (buffer-file-name))
  11361               (dir (locate-dominating-file filename "conf.py")))
  11362     (expand-file-name dir)))
  11363 
  11364 (flycheck-define-checker rst
  11365   "A ReStructuredText (RST) syntax checker using Docutils.
  11366 
  11367 See URL `https://docutils.sourceforge.net/'."
  11368   ;; include:: directives
  11369   :command ("rst2pseudoxml.py" "--report=2" "--halt=5"
  11370             ;; Read from standard input and throw output away
  11371             "-" null-device)
  11372   :standard-input t
  11373   :error-patterns
  11374   ((warning line-start "<stdin>:" line ": (WARNING/2) " (message) line-end)
  11375    (error line-start "<stdin>:" line
  11376           ": (" (or "ERROR/3" "SEVERE/4") ") "
  11377           (message) line-end))
  11378   :modes rst-mode)
  11379 
  11380 (flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx
  11381   "Whether to warn about missing references in Sphinx.
  11382 
  11383 When non-nil (the default), warn about all missing references in
  11384 Sphinx via `-n'."
  11385   :type 'boolean
  11386   :safe #'booleanp
  11387   :package-version '(flycheck . "0.17"))
  11388 
  11389 (flycheck-define-checker rst-sphinx
  11390   "A ReStructuredText (RST) syntax checker using Sphinx.
  11391 
  11392 Requires Sphinx 1.2 or newer.  See URL `https://sphinx-doc.org'."
  11393   :command ("sphinx-build" "-b" "pseudoxml"
  11394             "-q" "-N"                   ; Reduced output and no colors
  11395             (option-flag "-n" flycheck-sphinx-warn-on-missing-references)
  11396             (eval (flycheck-locate-sphinx-source-directory))
  11397             temporary-directory         ; Redirect the output to a temporary
  11398                                         ; directory
  11399             source-original)            ; Sphinx needs the original document
  11400   :error-patterns
  11401   ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end)
  11402    (error line-start
  11403           (file-name) ":" line
  11404           ": " (or "ERROR" "SEVERE") ": "
  11405           (message) line-end))
  11406   :modes rst-mode
  11407   :predicate (lambda () (and (flycheck-buffer-saved-p)
  11408                              (flycheck-locate-sphinx-source-directory))))
  11409 
  11410 (defun flycheck-ruby--find-project-root (_checker)
  11411   "Compute an appropriate working-directory for flycheck-ruby.
  11412 
  11413 This is either a parent directory containing a Gemfile, or nil."
  11414   (and
  11415    buffer-file-name
  11416    (locate-dominating-file buffer-file-name "Gemfile")))
  11417 
  11418 (defun flycheck-ruby--filter-rubocop-errors (errors)
  11419   "Filter RuboCop ERRORS attributed to dummy stdin filename."
  11420   (flycheck-remove-error-file-names
  11421    (flycheck--file-truename (expand-file-name "stdin"))
  11422    errors))
  11423 
  11424 (flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml")
  11425 
  11426 (flycheck-def-option-var flycheck-rubocop-lint-only nil
  11427                          (ruby-rubocop ruby-standard ruby-chef-cookstyle)
  11428   "Whether to only report code issues in Rubocop, Cookstyle and Standard.
  11429 
  11430 When non-nil, only report code issues, via `--lint'.  Otherwise
  11431 report style issues as well."
  11432   :safe #'booleanp
  11433   :type 'boolean
  11434   :package-version '(flycheck . "0.16"))
  11435 
  11436 (defconst flycheck-ruby-rubocop-error-patterns
  11437   '((info line-start (file-name) ":" line ":" column ": C: "
  11438           (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
  11439     (warning line-start (file-name) ":" line ":" column ": W: "
  11440              (optional (id (one-or-more (not (any ":")))) ": ") (message)
  11441              line-end)
  11442     (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
  11443            (optional (id (one-or-more (not (any ":")))) ": ") (message)
  11444            line-end)))
  11445 
  11446 (flycheck-def-executable-var ruby-rubocop "rubocop")
  11447 (flycheck-define-command-checker 'ruby-rubocop
  11448   "A Ruby syntax and style checker using the RuboCop tool.
  11449 
  11450 You need at least RuboCop 0.34 for this syntax checker.
  11451 
  11452 See URL `https://rubocop.org/'."
  11453   ;; ruby-standard is defined based on this checker
  11454   :command '("rubocop"
  11455              "--display-cop-names"
  11456              "--force-exclusion"
  11457              "--format" "emacs"
  11458              (config-file "--config" flycheck-rubocoprc)
  11459              (option-flag "--lint" flycheck-rubocop-lint-only)
  11460              ;; RuboCop takes the original file name as argument when reading
  11461              ;; from standard input, but it chokes when that name is the empty
  11462              ;; string, so fall back to "stdin" in order to handle buffers with
  11463              ;; no backing file (e.g. org-mode snippet buffers)
  11464              "--stdin" (eval (or (buffer-file-name) "stdin")))
  11465   :standard-input t
  11466   :working-directory #'flycheck-ruby--find-project-root
  11467   :error-patterns flycheck-ruby-rubocop-error-patterns
  11468   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11469   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11470   :next-checkers '((warning . ruby-reek)
  11471                    (warning . ruby-chef-cookstyle)))
  11472 
  11473 (flycheck-def-executable-var ruby-chef-cookstyle "cookstyle")
  11474 (flycheck-define-command-checker 'ruby-chef-cookstyle
  11475   "A Chef (Ruby) syntax and style checker using the Cookstyle tool.
  11476 Basically Cookstyle is a thin wrapper around RuboCop, so this
  11477 checker is essentially the same.
  11478 
  11479 See URL `https://github.com/chef/cookstyle'."
  11480   :command '("cookstyle"
  11481              "--display-cop-names"
  11482              "--force-exclusion"
  11483              "--format" "emacs"
  11484              (config-file "--config" flycheck-rubocoprc)
  11485              (option-flag "--lint" flycheck-rubocop-lint-only)
  11486              ;; RuboCop takes the original file name as argument when reading
  11487              ;; from standard input, but it chokes when that name is the empty
  11488              ;; string, so fall back to "stdin" in order to handle buffers with
  11489              ;; no backing file (e.g. org-mode snippet buffers)
  11490              "--stdin" (eval (or (buffer-file-name) "stdin")))
  11491   :standard-input t
  11492   :working-directory #'flycheck-ruby--find-project-root
  11493   :error-patterns flycheck-ruby-rubocop-error-patterns
  11494   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11495   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11496   :predicate
  11497   (lambda ()
  11498     (let ((parent-dir (file-name-directory
  11499                        (directory-file-name
  11500                         (expand-file-name default-directory)))))
  11501       (or
  11502        ;; Chef CookBook
  11503        ;; https://docs.opscode.com/chef/knife.html#id38
  11504        (locate-dominating-file parent-dir "recipes")
  11505        ;; Knife Solo
  11506        ;; https://matschaffer.github.io/knife-solo/#label-Init+command
  11507        (locate-dominating-file parent-dir "cookbooks"))))
  11508   :next-checkers '((warning . ruby-reek)))
  11509 
  11510 (flycheck-def-config-file-var flycheck-ruby-standardrc ruby-standard
  11511                               ".standard.yml")
  11512 
  11513 (flycheck-def-executable-var ruby-standard "standardrb")
  11514 (flycheck-define-command-checker 'ruby-standard
  11515   "A Ruby syntax and style checker using the StandardRB gem.
  11516 
  11517 See URL `https://github.com/testdouble/standard' for more information."
  11518   ;; This checker is derived from ruby-rubocop; see above
  11519   :command '("standardrb"
  11520              "--display-cop-names"
  11521              "--force-exclusion"
  11522              "--format" "emacs"
  11523              "--cache" "false"
  11524              (config-file "--config" flycheck-ruby-standardrc)
  11525              (option-flag "--lint" flycheck-rubocop-lint-only)
  11526              "--stdin" source-original)
  11527   :standard-input t
  11528   :working-directory #'flycheck-ruby--find-project-root
  11529   :error-patterns flycheck-ruby-rubocop-error-patterns
  11530   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11531   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11532   :next-checkers '((warning . ruby-reek)
  11533                    (warning . ruby-chef-cookstyle)))
  11534 
  11535 (flycheck-def-config-file-var flycheck-reekrc ruby-reek ".reek.yml"
  11536   :safe #'string-or-null-p
  11537   :package-version '(flycheck . "30"))
  11538 
  11539 (flycheck-define-checker ruby-reek
  11540   "A Ruby smell checker using reek.
  11541 
  11542 See URL `https://github.com/troessner/reek'."
  11543   :command ("reek" "--format" "json"
  11544             (config-file "--config" flycheck-reekrc)
  11545             source)
  11546   :error-parser flycheck-parse-reek
  11547   :modes (enh-ruby-mode ruby-mode ruby-ts-mode))
  11548 
  11549 (flycheck-define-checker ruby
  11550   "A Ruby syntax checker using the standard Ruby interpreter.
  11551 
  11552 Please note that the output of different Ruby versions and
  11553 implementations varies wildly.  This syntax checker supports
  11554 current versions of MRI and JRuby, but may break when used with
  11555 other implementations or future versions of these
  11556 implementations.
  11557 
  11558 Please consider using `ruby-rubocop' or `ruby-reek' instead.
  11559 
  11560 See URL `https://www.ruby-lang.org/'."
  11561   :command ("ruby" "-w" "-c")
  11562   :standard-input t
  11563   :error-patterns
  11564   ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv
  11565   ((error line-start "SyntaxError in -:" line ": " (message) line-end)
  11566    (warning line-start "-:" line ":" (optional column ":")
  11567             " warning: " (message) line-end)
  11568    (error line-start "-:" line ": " (message) line-end))
  11569   :modes (enh-ruby-mode ruby-mode ruby-ts-mode)
  11570   :next-checkers ((warning . ruby-chef-cookstyle)))
  11571 
  11572 (flycheck-define-checker ruby-jruby
  11573   "A Ruby syntax checker using the JRuby interpreter.
  11574 
  11575 This syntax checker is very primitive, and may break on future
  11576 versions of JRuby.
  11577 
  11578 Please consider using `ruby-rubocop' instead.
  11579 
  11580 See URL `https://jruby.org/'."
  11581   :command ("jruby" "-w" "-c")
  11582   :standard-input t
  11583   :error-patterns
  11584   ((error   line-start "SyntaxError in -:" line ": " (message) line-end)
  11585    (warning line-start "-:" line ": warning: " (message) line-end)
  11586    (error   line-start "-:" line ": "          (message) line-end))
  11587   :modes (enh-ruby-mode ruby-mode ruby-ts-mode))
  11588 
  11589 (flycheck-def-args-var flycheck-cargo-check-args (rust-cargo)
  11590   :package-version '(flycheck . "32"))
  11591 
  11592 (flycheck-def-args-var flycheck-rust-args (rust)
  11593   :package-version '(flycheck . "0.24"))
  11594 
  11595 (flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust)
  11596   "Whether to check test code in Rust.
  11597 
  11598 For the `rust' checker: When non-nil, `rustc' is passed the
  11599 `--test' flag, which will check any code marked with the
  11600 `#[cfg(test)]' attribute and any functions marked with
  11601 `#[test]'. Otherwise, `rustc' is not passed `--test' and test
  11602 code will not be checked.  Skipping `--test' is necessary when
  11603 using `#![no_std]', because compiling the test runner requires
  11604 `std'.
  11605 
  11606 For the `rust-cargo' checker: When non-nil, calls `cargo test
  11607 --no-run' instead of `cargo check'."
  11608   :type 'boolean
  11609   :safe #'booleanp
  11610   :package-version '("flycheck" . "0.19"))
  11611 
  11612 (flycheck-def-option-var flycheck-rust-crate-root nil rust
  11613   "A path to the crate root for the current buffer.
  11614 
  11615 The value of this variable is either a string with the path to
  11616 the crate root for the current buffer, or nil if the current buffer
  11617 is a crate.  A relative path is relative to the current buffer.
  11618 
  11619 If this variable is non nil the current buffer will only be checked
  11620 if it is not modified, i.e. after it has been saved."
  11621   :type '(choice (const :tag "Unspecified" nil)
  11622                  (file :tag "Root"))
  11623   :safe #'flycheck-string-or-nil-p
  11624   :package-version '(flycheck . "0.20"))
  11625 (make-variable-buffer-local 'flycheck-rust-crate-root)
  11626 
  11627 (flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust)
  11628   "The type of the Rust Crate to check.
  11629 
  11630 For `rust-cargo', the value should be a string denoting the
  11631 target type passed to Cargo.  See
  11632 `flycheck-rust-valid-crate-type-p' for the list of allowed
  11633 values.
  11634 
  11635 For `rust', the value should be a string denoting the crate type
  11636 for the `--crate-type' flag of rustc."
  11637   :type '(choice (const :tag "nil (rust/rust-cargo)" nil)
  11638                  (const :tag "lib (rust/rust-cargo)" "lib")
  11639                  (const :tag "bin (rust/rust-cargo)" "bin")
  11640                  (const :tag "example (rust-cargo)" "example")
  11641                  (const :tag "test (rust-cargo)" "test")
  11642                  (const :tag "bench (rust-cargo)" "bench")
  11643                  (const :tag "rlib (rust)" "rlib")
  11644                  (const :tag "dylib (rust)" "dylib")
  11645                  (const :tag "cdylib (rust)" "cdylib")
  11646                  (const :tag "staticlib (rust)" "staticlib")
  11647                  (const :tag "metadata (rust)" "metadata"))
  11648   :safe #'stringp
  11649   :package-version '(flycheck . "0.20"))
  11650 (make-variable-buffer-local 'flycheck-rust-crate-type)
  11651 
  11652 (flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo
  11653   "The name of the binary to pass to `cargo check --CRATE-TYPE'.
  11654 
  11655 The value of this variable is a string denoting the name of the
  11656 target to check: usually the name of the crate, or the name of
  11657 one of the files under `src/bin', `tests', `examples' or
  11658 `benches'.
  11659 
  11660 This always requires a non-nil value, unless
  11661 `flycheck-rust-crate-type' is `lib' or nil, in which case it is
  11662 ignored."
  11663   :type '(choice (const :tag "Unspecified" nil)
  11664                  (string :tag "Binary name"))
  11665   :safe #'flycheck-string-or-nil-p
  11666   :package-version '(flycheck . "28"))
  11667 (make-variable-buffer-local 'flycheck-rust-binary-name)
  11668 
  11669 (flycheck-def-option-var flycheck-rust-features nil rust-cargo
  11670   "List of features to activate during build or check.
  11671 
  11672 The value of this variable is a list of strings denoting features
  11673 that will be activated to build the target to check. Features will
  11674 be passed to `cargo check --features=FEATURES'."
  11675   :type '(repeat :tag "Features to activate"
  11676                  (string :tag "Feature"))
  11677   :safe #'flycheck-string-list-p
  11678   :package-version '(flycheck . "32"))
  11679 (make-variable-buffer-local 'flycheck-rust-features)
  11680 
  11681 (flycheck-def-option-var flycheck-rust-library-path nil rust
  11682   "A list of library directories for Rust.
  11683 
  11684 The value of this variable is a list of strings, where each
  11685 string is a directory to add to the library path of Rust.
  11686 Relative paths are relative to the file being checked."
  11687   :type '(repeat (directory :tag "Library directory"))
  11688   :safe #'flycheck-string-list-p
  11689   :package-version '(flycheck . "0.18"))
  11690 
  11691 (defun flycheck--fontify-as-markdown ()
  11692   "Place current buffer in `markdown-view-mode' and fontify it."
  11693   (when (fboundp 'markdown-view-mode)
  11694     (let ((markdown-fontify-code-block-default-mode 'rust-mode)
  11695           (markdown-fontify-code-blocks-natively t)
  11696           (markdown-hide-markup t))
  11697       (markdown-view-mode)
  11698       (font-lock-flush)
  11699       (font-lock-ensure))))
  11700 
  11701 (defun flycheck-rust-error-explainer (error)
  11702   "Return an explanation for the given `flycheck-error' ERROR."
  11703   (when-let (error-code (flycheck-error-id error))
  11704     (lambda ()
  11705       (flycheck-call-checker-process
  11706        'rust nil standard-output t "--explain" error-code)
  11707       (with-current-buffer standard-output
  11708         (flycheck--fontify-as-markdown)))))
  11709 
  11710 (defun flycheck-rust-error-filter (errors)
  11711   "Filter ERRORS from rustc output that have no explanatory value."
  11712   (seq-remove
  11713    (lambda (err)
  11714      (or
  11715       ;; Macro errors emit a diagnostic in a phony file,
  11716       ;; e.g. "<println macros>".
  11717       (when-let (filename (flycheck-error-filename err))
  11718         (string-match-p (rx "macros>" line-end) filename))
  11719       ;; Redundant message giving the number of failed errors
  11720       (when-let (msg (flycheck-error-message err))
  11721         (string-match-p
  11722          (rx
  11723           (or (: "aborting due to " (optional (one-or-more num) " ")
  11724                  "previous error")
  11725               (: "For more information about this error, try `rustc --explain "
  11726                  (one-or-more alnum) "`.")))
  11727          msg))))
  11728    errors))
  11729 
  11730 (defun flycheck-rust-manifest-directory ()
  11731   "Return the nearest directory holding the Cargo manifest.
  11732 
  11733 Return the nearest directory containing the `Cargo.toml' manifest
  11734 file, starting from the current buffer and using
  11735 `locate-dominating-file'.  Return nil if there is no such file,
  11736 or if the current buffer has no file name."
  11737   (and buffer-file-name
  11738        (locate-dominating-file buffer-file-name "Cargo.toml")))
  11739 
  11740 (defun flycheck-rust-cargo-metadata ()
  11741   "Run `cargo metadata' and return the result as parsed JSON object."
  11742   (car (flycheck-parse-json
  11743         (flycheck-call-checker-process-for-output
  11744          'rust-cargo nil t
  11745          "metadata" "--no-deps" "--format-version" "1"))))
  11746 
  11747 (defun flycheck-rust-cargo-workspace-root ()
  11748   "Return the path to the workspace root of a Rust Cargo project.
  11749 
  11750 Return nil if the workspace root does not exist (for Rust
  11751 versions inferior to 1.25)."
  11752   (let-alist (flycheck-rust-cargo-metadata)
  11753     .workspace_root))
  11754 
  11755 (defun flycheck-rust-cargo-has-command-p (command)
  11756   "Whether Cargo has COMMAND in its list of commands.
  11757 
  11758 Execute `cargo --list' to find out whether COMMAND is present."
  11759   (let ((cargo (funcall flycheck-executable-find "cargo")))
  11760     (member command
  11761             (mapcar (lambda (line)
  11762                       (replace-regexp-in-string "\\s-*\\(\\S-+\\).*\\'" "\\1" line))
  11763                     (ignore-errors (process-lines cargo "--list"))))))
  11764 
  11765 (defun flycheck-rust-valid-crate-type-p (crate-type)
  11766   "Whether CRATE-TYPE is a valid target type for Cargo.
  11767 
  11768 A valid Cargo target type is one of `lib', `bin', `example',
  11769 `test' or `bench'."
  11770   (member crate-type '(nil "lib" "bin" "example" "test" "bench")))
  11771 
  11772 (flycheck-define-checker rust-cargo
  11773   "A Rust syntax checker using Cargo.
  11774 
  11775 This syntax checker requires Rust 1.17 or newer.  See URL
  11776 `https://www.rust-lang.org'."
  11777   :command ("cargo"
  11778             (eval (if flycheck-rust-check-tests
  11779                       "test"
  11780                     "check"))
  11781             (eval (when flycheck-rust-check-tests
  11782                     "--no-run"))
  11783             (eval (when flycheck-rust-crate-type
  11784                     (concat "--" flycheck-rust-crate-type)))
  11785             ;; All crate targets except "lib" need a binary name
  11786             (eval (when (and flycheck-rust-crate-type
  11787                              (not (string= flycheck-rust-crate-type "lib")))
  11788                     flycheck-rust-binary-name))
  11789             (option "--features=" flycheck-rust-features concat
  11790                     flycheck-option-comma-separated-list)
  11791             (eval flycheck-cargo-check-args)
  11792             "--message-format=json")
  11793   :error-parser flycheck-parse-cargo-rustc
  11794   :error-filter (lambda (errors)
  11795                   ;; In Rust 1.25+, filenames are relative to the workspace
  11796                   ;; root.
  11797                   (let ((root (flycheck-rust-cargo-workspace-root)))
  11798                     (seq-do (lambda (err)
  11799                               ;; Some errors are crate level and do not have a
  11800                               ;; filename
  11801                               (when (flycheck-error-filename err)
  11802                                 (setf (flycheck-error-filename err)
  11803                                       (expand-file-name
  11804                                        (flycheck-error-filename err) root))))
  11805                             (flycheck-rust-error-filter errors))))
  11806   :error-explainer flycheck-rust-error-explainer
  11807   :modes (rust-mode rust-ts-mode)
  11808   :predicate flycheck-buffer-saved-p
  11809   :enabled flycheck-rust-manifest-directory
  11810   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
  11811   :verify
  11812   (lambda (_)
  11813     (and buffer-file-name
  11814          (let* ((has-toml (flycheck-rust-manifest-directory))
  11815                 (valid-crate-type (flycheck-rust-valid-crate-type-p
  11816                                    flycheck-rust-crate-type))
  11817                 (need-binary-name
  11818                  (and flycheck-rust-crate-type
  11819                       (not (string= flycheck-rust-crate-type "lib")))))
  11820            (list
  11821             (flycheck-verification-result-new
  11822              :label "Cargo.toml"
  11823              :message (if has-toml "Found" "Missing")
  11824              :face (if has-toml 'success '(bold warning)))
  11825             (flycheck-verification-result-new
  11826              :label "Crate type"
  11827              :message (if valid-crate-type
  11828                           (format "%s" flycheck-rust-crate-type)
  11829                         (format "%s (invalid, should be one of 'lib', 'bin', \
  11830 'test', 'example' or 'bench')"
  11831                                 flycheck-rust-crate-type))
  11832              :face (if valid-crate-type 'success '(bold error)))
  11833             (flycheck-verification-result-new
  11834              :label "Binary name"
  11835              :message (cond
  11836                        ((not need-binary-name) "Not required")
  11837                        ((not flycheck-rust-binary-name) "Required")
  11838                        (t (format "%s" flycheck-rust-binary-name)))
  11839              :face (cond
  11840                     ((not need-binary-name) 'success)
  11841                     ((not flycheck-rust-binary-name) '(bold error))
  11842                     (t 'success))))))))
  11843 
  11844 (flycheck-define-checker rust
  11845   "A Rust syntax checker using Rust compiler.
  11846 
  11847 This syntax checker needs Rust 1.18 or newer.  See URL
  11848 `https://www.rust-lang.org'."
  11849   :command ("rustc"
  11850             (option "--crate-type" flycheck-rust-crate-type)
  11851             "--emit=mir" "-o" "/dev/null" ; avoid creating binaries
  11852             "--error-format=json"
  11853             (option-flag "--test" flycheck-rust-check-tests)
  11854             (option-list "-L" flycheck-rust-library-path concat)
  11855             (eval flycheck-rust-args)
  11856             (eval (or flycheck-rust-crate-root
  11857                       (flycheck-substitute-argument 'source-original 'rust))))
  11858   :error-parser flycheck-parse-rustc
  11859   :error-filter flycheck-rust-error-filter
  11860   :error-explainer flycheck-rust-error-explainer
  11861   :modes (rust-mode rust-ts-mode)
  11862   :predicate flycheck-buffer-saved-p)
  11863 
  11864 (flycheck-define-checker rust-clippy
  11865   "A Rust syntax checker using clippy.
  11866 
  11867 See URL `https://github.com/rust-lang-nursery/rust-clippy'."
  11868   :command ("cargo" "clippy" "--message-format=json")
  11869   :error-parser flycheck-parse-cargo-rustc
  11870   :error-filter flycheck-rust-error-filter
  11871   :error-explainer flycheck-rust-error-explainer
  11872   :modes (rust-mode rust-ts-mode)
  11873   :predicate flycheck-buffer-saved-p
  11874   :enabled (lambda ()
  11875              (and (flycheck-rust-cargo-has-command-p "clippy")
  11876                   (flycheck-rust-manifest-directory)))
  11877   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
  11878   :verify
  11879   (lambda (_)
  11880     (and buffer-file-name
  11881          (let ((has-toml (flycheck-rust-manifest-directory))
  11882                (has-clippy (flycheck-rust-cargo-has-command-p "clippy")))
  11883            (list
  11884             (flycheck-verification-result-new
  11885              :label "Clippy"
  11886              :message (if has-clippy "Found"
  11887                         "Cannot find the `cargo clippy' command")
  11888              :face (if has-clippy 'success '(bold warning)))
  11889             (flycheck-verification-result-new
  11890              :label "Cargo.toml"
  11891              :message (if has-toml "Found" "Missing")
  11892              :face (if has-toml 'success '(bold warning))))))))
  11893 
  11894 (defvar flycheck-sass-scss-cache-directory nil
  11895   "The cache directory for `sass' and `scss'.")
  11896 
  11897 (defun flycheck-sass-scss-cache-location ()
  11898   "Get the cache location for `sass' and `scss'.
  11899 
  11900 If no cache directory exists yet, create one and return it.
  11901 Otherwise return the previously used cache directory."
  11902   (setq flycheck-sass-scss-cache-directory
  11903         (or flycheck-sass-scss-cache-directory
  11904             (make-temp-file "flycheck-sass-scss-cache" 'directory))))
  11905 
  11906 (flycheck-def-option-var flycheck-sass-compass nil sass
  11907   "Whether to enable the Compass CSS framework.
  11908 
  11909 When non-nil, enable the Compass CSS framework, via `--compass'."
  11910   :type 'boolean
  11911   :safe #'booleanp
  11912   :package-version '(flycheck . "0.16"))
  11913 
  11914 (flycheck-define-checker sass
  11915   "A Sass syntax checker using the Sass compiler.
  11916 
  11917 See URL `https://sass-lang.com'."
  11918   :command ("sass"
  11919             "--cache-location" (eval (flycheck-sass-scss-cache-location))
  11920             (option-flag "--compass" flycheck-sass-compass)
  11921             "--check" "--stdin")
  11922   :standard-input t
  11923   :error-patterns
  11924   ((error line-start
  11925           (or "Syntax error: " "Error: ")
  11926           (message (one-or-more not-newline)
  11927                    (zero-or-more "\n"
  11928                                  (one-or-more " ")
  11929                                  (one-or-more not-newline)))
  11930           (optional "\r") "\n" (one-or-more " ") "on line " line
  11931           " of standard input"
  11932           line-end)
  11933    (warning line-start
  11934             "WARNING: "
  11935             (message (one-or-more not-newline)
  11936                      (zero-or-more "\n"
  11937                                    (one-or-more " ")
  11938                                    (one-or-more not-newline)))
  11939             (optional "\r") "\n" (one-or-more " ") "on line " line
  11940             " of " (one-or-more not-newline)
  11941             line-end))
  11942   :modes sass-mode)
  11943 
  11944 (flycheck-def-config-file-var flycheck-sass-lintrc sass/scss-sass-lint
  11945                               ".sass-lint.yml"
  11946   :package-version '(flycheck . "30"))
  11947 
  11948 (flycheck-define-checker sass/scss-sass-lint
  11949   "A SASS/SCSS syntax checker using sass-Lint.
  11950 
  11951 See URL `https://github.com/sasstools/sass-lint'."
  11952   :command ("sass-lint"
  11953             "--verbose"
  11954             "--no-exit"
  11955             "--format" "Checkstyle"
  11956             (config-file "--config" flycheck-sass-lintrc)
  11957             source)
  11958   :error-parser flycheck-parse-checkstyle
  11959   :modes (sass-mode scss-mode))
  11960 
  11961 (flycheck-define-checker scala
  11962   "A Scala syntax checker using the Scala compiler.
  11963 
  11964 See URL `https://www.scala-lang.org/'."
  11965   :command ("scalac" "-Ystop-after:parser" source)
  11966   :error-patterns
  11967   ((error line-start (file-name) ":" line ": error: " (message) line-end))
  11968   :modes scala-mode
  11969   :next-checkers ((warning . scala-scalastyle)))
  11970 
  11971 (flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil
  11972   :package-version '(flycheck . "0.20"))
  11973 
  11974 (flycheck-define-checker scala-scalastyle
  11975   "A Scala style checker using scalastyle.
  11976 
  11977 Note that this syntax checker is not used if
  11978 `flycheck-scalastylerc' is nil or refers to a non-existing file.
  11979 
  11980 See URL `https://www.scalastyle.org'."
  11981   :command ("scalastyle"
  11982             (config-file "-c" flycheck-scalastylerc)
  11983             source)
  11984   :error-patterns
  11985   ((error line-start "error file=" (file-name) " message="
  11986           (message) " line=" line (optional " column=" column) line-end)
  11987    (warning line-start "warning file=" (file-name) " message="
  11988             (message) " line=" line (optional " column=" column) line-end))
  11989   :error-filter (lambda (errors)
  11990                   (flycheck-sanitize-errors
  11991                    (flycheck-increment-error-columns errors)))
  11992   :modes scala-mode
  11993   :predicate
  11994   ;; Inhibit this syntax checker if the JAR or the configuration are unset or
  11995   ;; missing
  11996   (lambda () (and flycheck-scalastylerc
  11997                   (flycheck-locate-config-file flycheck-scalastylerc
  11998                                                'scala-scalastyle)))
  11999   :verify (lambda (checker)
  12000             (let ((config-file (and flycheck-scalastylerc
  12001                                     (flycheck-locate-config-file
  12002                                      flycheck-scalastylerc checker))))
  12003               (list
  12004                (flycheck-verification-result-new
  12005                 :label "Configuration file"
  12006                 :message (cond
  12007                           ((not flycheck-scalastylerc)
  12008                            "`flycheck-scalastyletrc' not set")
  12009                           ((not config-file)
  12010                            (format "file %s not found" flycheck-scalastylerc))
  12011                           (t (format "found at %s" config-file)))
  12012                 :face (cond
  12013                        ((not flycheck-scalastylerc) '(bold warning))
  12014                        ((not config-file) '(bold error))
  12015                        (t 'success)))))))
  12016 
  12017 (flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken
  12018   :package-version '(flycheck . "32"))
  12019 
  12020 (flycheck-define-checker scheme-chicken
  12021   "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'.
  12022 
  12023 See URL `https://call-cc.org/'."
  12024   :command ("csc" "-analyze-only" "-local"
  12025             (eval flycheck-scheme-chicken-args)
  12026             source)
  12027   :error-patterns
  12028   ((info line-start
  12029          "Note: " (zero-or-more not-newline) ":\n"
  12030          (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12031          line-end)
  12032    (warning line-start
  12033             "Warning: " (zero-or-more not-newline) ",\n"
  12034             (one-or-more (any space)) (zero-or-more not-newline) ":\n"
  12035             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12036             line-end)
  12037    (warning line-start
  12038             "Warning: " (zero-or-more not-newline) ":\n"
  12039             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12040             line-end)
  12041    (error line-start "Error: (line " line ") " (message) line-end)
  12042    (error line-start "Syntax error: (" (file-name) ":" line ")"
  12043           (zero-or-more not-newline) " - "
  12044           (message (one-or-more not-newline)
  12045                    (zero-or-more "\n"
  12046                                  (zero-or-more space)
  12047                                  (zero-or-more not-newline))
  12048                    (one-or-more space) "<--")
  12049           line-end)
  12050    ;; A of version 4.12.0, the chicken compiler doesn't provide a
  12051    ;; line number for this error.
  12052    (error line-start "Syntax error: "
  12053           (message (one-or-more not-newline)
  12054                    (zero-or-more "\n"
  12055                                  (zero-or-more space)
  12056                                  (zero-or-more not-newline))
  12057                    (one-or-more space) "<--")
  12058           line-end)
  12059    (error line-start
  12060           "Error: " (zero-or-more not-newline) ":\n"
  12061           (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12062           line-end)
  12063    ;; A of version 4.12.0, the chicken compiler doesn't provide a
  12064    ;; line number for this error.
  12065    (error line-start "Error: "
  12066           (message (one-or-more not-newline)
  12067                    (zero-or-more "\n"
  12068                                  (zero-or-more space)
  12069                                  (zero-or-more not-newline))
  12070                    (one-or-more space) "<--")))
  12071   :error-filter flycheck-fill-empty-line-numbers
  12072   :predicate
  12073   (lambda ()
  12074     ;; In `scheme-mode' we must check the current Scheme implementation
  12075     ;; being used
  12076     (and (boundp 'geiser-impl--implementation)
  12077          (eq geiser-impl--implementation 'chicken)))
  12078   :verify
  12079   (lambda (_checker)
  12080     (let ((geiser-impl (bound-and-true-p geiser-impl--implementation)))
  12081       (list
  12082        (flycheck-verification-result-new
  12083         :label "Geiser Implementation"
  12084         :message (cond
  12085                   ((eq geiser-impl 'chicken) "Chicken Scheme")
  12086                   (geiser-impl (format "Other: %s" geiser-impl))
  12087                   (t "Geiser not active"))
  12088         :face (cond
  12089                ((eq geiser-impl 'chicken) 'success)
  12090                (t '(bold error)))))))
  12091   :modes scheme-mode)
  12092 
  12093 (defconst flycheck-scss-lint-checkstyle-re
  12094   (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle")
  12095   "Regular expression to parse missing checkstyle error.")
  12096 
  12097 (defun flycheck-parse-scss-lint (output checker buffer)
  12098   "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER.
  12099 
  12100 Like `flycheck-parse-checkstyle', but catches errors about
  12101 missing checkstyle reporter from SCSS-Lint."
  12102   (if (string-match-p flycheck-scss-lint-checkstyle-re output)
  12103       (list (flycheck-error-new-at
  12104              1 nil 'error "Checkstyle reporter for SCSS-Lint missing.
  12105 Please run gem install scss_lint_reporter_checkstyle"
  12106              :checker checker
  12107              :buffer buffer
  12108              :filename (buffer-file-name buffer)))
  12109     (flycheck-parse-checkstyle output checker buffer)))
  12110 
  12111 (flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml"
  12112   :package-version '(flycheck . "0.23"))
  12113 
  12114 (flycheck-define-checker scss-lint
  12115   "A SCSS syntax checker using SCSS-Lint.
  12116 
  12117 Needs SCSS-Lint 0.43.2 or newer.
  12118 
  12119 See URL `https://github.com/brigade/scss-lint'."
  12120   :command ("scss-lint"
  12121             "--require=scss_lint_reporter_checkstyle"
  12122             "--format=Checkstyle"
  12123             (config-file "--config" flycheck-scss-lintrc)
  12124             "--stdin-file-path" source-original "-")
  12125   :standard-input t
  12126   ;; We cannot directly parse Checkstyle XML, since for some mysterious reason
  12127   ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it
  12128   ;; as an addon which might not be installed.  We use a custom error parser to
  12129   ;; check whether the addon is missing and turn that into a special kind of
  12130   ;; Flycheck error.
  12131   :error-parser flycheck-parse-scss-lint
  12132   :modes scss-mode
  12133   :verify
  12134   (lambda (checker)
  12135     (when-let
  12136         (output (flycheck-call-checker-process-for-output
  12137                  checker nil nil "--require=scss_lint_reporter_checkstyle"))
  12138       (let ((reporter-missing
  12139              (string-match-p flycheck-scss-lint-checkstyle-re output)))
  12140         (list
  12141          (flycheck-verification-result-new
  12142           :label "checkstyle reporter"
  12143           :message (if reporter-missing
  12144                        "scss_lint_reporter_checkstyle plugin missing"
  12145                      "present")
  12146           :face (if reporter-missing
  12147                     '(bold error)
  12148                   'success)))))))
  12149 
  12150 (flycheck-define-checker scss-stylelint
  12151   "A SCSS syntax and style checker using stylelint.
  12152 
  12153 See URL `https://stylelint.io/'."
  12154   :command ("stylelint"
  12155             (eval flycheck-stylelint-args)
  12156             (option-flag "--quiet" flycheck-stylelint-quiet)
  12157             (config-file "--config" flycheck-stylelintrc))
  12158   :standard-input t
  12159   :verify (lambda (_) (flycheck--stylelint-verify 'scss-stylelint))
  12160   :error-parser flycheck-parse-stylelint
  12161   :predicate flycheck-buffer-nonempty-p
  12162   :modes (scss-mode))
  12163 
  12164 (flycheck-define-checker sass-stylelint
  12165   "A Sass syntax and style checker using stylelint.
  12166 
  12167 See URL `https://stylelint.io/'."
  12168   :command ("stylelint"
  12169             (eval flycheck-stylelint-args)
  12170             (option-flag "--quiet" flycheck-stylelint-quiet)
  12171             (config-file "--config" flycheck-stylelintrc))
  12172   :standard-input t
  12173   :verify (lambda (_) (flycheck--stylelint-verify 'sass-stylelint))
  12174   :error-parser flycheck-parse-stylelint
  12175   :predicate flycheck-buffer-nonempty-p
  12176   :modes (sass-mode))
  12177 
  12178 (flycheck-def-option-var flycheck-scss-compass nil scss
  12179   "Whether to enable the Compass CSS framework.
  12180 
  12181 When non-nil, enable the Compass CSS framework, via `--compass'."
  12182   :type 'boolean
  12183   :safe #'booleanp
  12184   :package-version '(flycheck . "0.16"))
  12185 
  12186 (flycheck-define-checker scss
  12187   "A SCSS syntax checker using the SCSS compiler.
  12188 
  12189 See URL `https://sass-lang.com'."
  12190   :command ("scss"
  12191             "--cache-location" (eval (flycheck-sass-scss-cache-location))
  12192             (option-flag "--compass" flycheck-scss-compass)
  12193             "--check" "--stdin")
  12194   :standard-input t
  12195   :error-patterns
  12196   ((error line-start
  12197           (or "Syntax error: " "Error: ")
  12198           (message (one-or-more not-newline)
  12199                    (zero-or-more "\n"
  12200                                  (one-or-more " ")
  12201                                  (one-or-more not-newline)))
  12202           (optional "\r") "\n" (one-or-more " ") "on line " line
  12203           " of standard input"
  12204           line-end)
  12205    (warning line-start
  12206             "WARNING: "
  12207             (message (one-or-more not-newline)
  12208                      (zero-or-more "\n"
  12209                                    (one-or-more " ")
  12210                                    (one-or-more not-newline)))
  12211             (optional "\r") "\n" (one-or-more " ") "on line " line
  12212             " of an unknown file"
  12213             line-end))
  12214   :modes scss-mode)
  12215 
  12216 (flycheck-def-args-var flycheck-sh-bash-args (sh-bash)
  12217   :package-version '(flycheck . "32"))
  12218 
  12219 (flycheck-define-checker sh-bash
  12220   "A Bash syntax checker using the Bash shell.
  12221 
  12222 See URL `https://www.gnu.org/software/bash/'."
  12223   :command ("bash" "--norc" "-n"
  12224             (eval flycheck-sh-bash-args)
  12225             "--")
  12226   :standard-input t
  12227   :error-patterns
  12228   ((error line-start
  12229           ;; The name/path of the bash executable
  12230           (one-or-more (not (any ":"))) ":"
  12231           ;; A label "line", possibly localized
  12232           (one-or-more (not (any digit)))
  12233           line (zero-or-more " ") ":" (zero-or-more " ")
  12234           (message) line-end))
  12235   :modes (sh-mode bash-ts-mode)
  12236   :predicate (lambda () (eq sh-shell 'bash))
  12237   :next-checkers ((warning . sh-shellcheck)))
  12238 
  12239 (flycheck-define-checker sh-posix-dash
  12240   "A POSIX Shell syntax checker using the Dash shell.
  12241 
  12242 See URL `https://gondor.apana.org.au/~herbert/dash/'."
  12243   :command ("dash" "-n")
  12244   :standard-input t
  12245   :error-patterns
  12246   ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message)))
  12247   :modes sh-mode
  12248   :predicate (lambda () (eq sh-shell 'sh))
  12249   :next-checkers ((warning . sh-shellcheck)))
  12250 
  12251 (flycheck-define-checker sh-posix-bash
  12252   "A POSIX Shell syntax checker using the Bash shell.
  12253 
  12254 See URL `https://www.gnu.org/software/bash/'."
  12255   :command ("bash" "--posix" "--norc" "-n" "--")
  12256   :standard-input t
  12257   :error-patterns
  12258   ((error line-start
  12259           ;; The name/path of the bash executable
  12260           (one-or-more (not (any ":"))) ":"
  12261           ;; A label "line", possibly localized
  12262           (one-or-more (not (any digit)))
  12263           line (zero-or-more " ") ":" (zero-or-more " ")
  12264           (message) line-end))
  12265   :modes sh-mode
  12266   :predicate (lambda () (eq sh-shell 'sh))
  12267   :next-checkers ((warning . sh-shellcheck)))
  12268 
  12269 (flycheck-define-checker sh-zsh
  12270   "A Zsh syntax checker using the Zsh shell.
  12271 
  12272 See URL `https://www.zsh.org/'."
  12273   :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source)
  12274   :error-patterns
  12275   ((error line-start (file-name) ":" line ": " (message) line-end))
  12276   :modes sh-mode
  12277   :predicate (lambda () (eq sh-shell 'zsh))
  12278   :next-checkers ((warning . sh-shellcheck)))
  12279 
  12280 (defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh)
  12281   "Shells supported by ShellCheck.")
  12282 
  12283 (flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck
  12284   "A list of excluded warnings for ShellCheck.
  12285 
  12286 The value of this variable is a list of strings, where each
  12287 string is a warning code to be excluded from ShellCheck reports.
  12288 By default, no warnings are excluded."
  12289   :type '(repeat :tag "Excluded warnings"
  12290                  (string :tag "Warning code"))
  12291   :safe #'flycheck-string-list-p
  12292   :package-version '(flycheck . "0.21"))
  12293 
  12294 (flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck
  12295   "Whether to follow external sourced files in scripts.
  12296 
  12297 Shellcheck will follow and parse sourced files so long as a
  12298 pre-runtime resolvable path to the file is present.  This can
  12299 either be part of the source command itself:
  12300    source /full/path/to/file.txt
  12301 or added as a shellcheck directive before the source command:
  12302    # shellcheck source=/full/path/to/file.txt."
  12303   :type 'boolean
  12304   :safe #'booleanp
  12305   :package-version '(flycheck . "31"))
  12306 
  12307 (flycheck-define-checker sh-shellcheck
  12308   "A shell script syntax and style checker using Shellcheck.
  12309 
  12310 See URL `https://github.com/koalaman/shellcheck/'."
  12311   :command ("shellcheck"
  12312             "--format" "checkstyle"
  12313             "--shell" (eval (symbol-name sh-shell))
  12314             (option-flag "--external-sources"
  12315                          flycheck-shellcheck-follow-sources)
  12316             (option "--exclude" flycheck-shellcheck-excluded-warnings list
  12317                     flycheck-option-comma-separated-list)
  12318             "-")
  12319   :standard-input t
  12320   :error-parser flycheck-parse-checkstyle
  12321   :error-filter
  12322   (lambda (errors)
  12323     (flycheck-remove-error-file-names
  12324      "-" (flycheck-dequalify-error-ids errors)))
  12325   :modes (sh-mode bash-ts-mode)
  12326   :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells))
  12327   :verify (lambda (_)
  12328             (let ((supports-shell (memq sh-shell
  12329                                         flycheck-shellcheck-supported-shells)))
  12330               (list
  12331                (flycheck-verification-result-new
  12332                 :label (format "Shell %s supported" sh-shell)
  12333                 :message (if supports-shell "yes" "no")
  12334                 :face (if supports-shell 'success '(bold warning))))))
  12335   :error-explainer
  12336   (lambda (err)
  12337     (let ((error-code (flycheck-error-id err))
  12338           (url "https://github.com/koalaman/shellcheck/wiki/%s"))
  12339       (and error-code `(url . ,(format url error-code))))))
  12340 
  12341 (flycheck-define-checker slim
  12342   "A Slim syntax checker using the Slim compiler.
  12343 
  12344 See URL `https://slim-lang.com'."
  12345   :command ("slimrb" "--compile")
  12346   :standard-input t
  12347   :error-patterns
  12348   ((error line-start
  12349           "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n  "
  12350           "STDIN, Line " line (optional ", Column " column)
  12351           line-end))
  12352   :modes slim-mode
  12353   :next-checkers ((warning . slim-lint)))
  12354 
  12355 (flycheck-define-checker slim-lint
  12356   "A Slim linter.
  12357 
  12358 See URL `https://github.com/sds/slim-lint'."
  12359   :command ("slim-lint" "--reporter=checkstyle" source)
  12360   :error-parser flycheck-parse-checkstyle
  12361   :modes slim-mode)
  12362 
  12363 (flycheck-define-checker sql-sqlint
  12364   "A SQL syntax checker using the sqlint tool.
  12365 
  12366 See URL `https://github.com/purcell/sqlint'."
  12367   :command ("sqlint")
  12368   :standard-input t
  12369   :error-patterns
  12370   ((warning line-start "stdin:" line ":" column ":WARNING "
  12371             (message (one-or-more not-newline)
  12372                      (zero-or-more "\n"
  12373                                    (one-or-more "  ")
  12374                                    (one-or-more not-newline)))
  12375             line-end)
  12376    (error line-start "stdin:" line ":" column ":ERROR "
  12377           (message (one-or-more not-newline)
  12378                    (zero-or-more "\n"
  12379                                  (one-or-more "  ")
  12380                                  (one-or-more not-newline)))
  12381           line-end))
  12382   :modes (sql-mode))
  12383 
  12384 (flycheck-define-checker systemd-analyze
  12385   "A systemd unit checker using systemd-analyze(1).
  12386 
  12387 See URL
  12388 `https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'."
  12389   :command ("systemd-analyze" "verify" source)
  12390   :error-parser flycheck-parse-with-patterns-without-color
  12391   :error-patterns
  12392   ((error line-start (file-name) ":" (optional line ":") (message) line-end)
  12393    (error line-start "[" (file-name) ":" line "]" (message) line-end))
  12394   :error-filter (lambda (errors)
  12395                   (flycheck-sanitize-errors
  12396                    (flycheck-fill-empty-line-numbers errors)))
  12397   :modes (systemd-mode))
  12398 
  12399 (flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc")
  12400 
  12401 (flycheck-define-checker tcl-nagelfar
  12402   "An extensible tcl syntax checker
  12403 
  12404 See URL `https://nagelfar.sourceforge.net/'."
  12405   :command ("nagelfar" "-H" source)
  12406   :error-patterns
  12407   ;; foo.tcl: 29: E Wrong number of arguments (4) to "set"
  12408   ;; foo.tcl: 29: W Expr without braces
  12409   ((info    line-start (file-name) ": " line ": N " (message) line-end)
  12410    (warning line-start (file-name) ": " line ": W " (message) line-end)
  12411    (error   line-start (file-name) ": " line ": E " (message) line-end))
  12412   :modes tcl-mode)
  12413 
  12414 (flycheck-define-checker terraform
  12415   "A Terraform syntax checker with `terraform fmt'.
  12416 
  12417 See URL `https://www.terraform.io/docs/commands/fmt.html'."
  12418   :command ("terraform" "fmt" "-no-color" "-")
  12419   :standard-input t
  12420   :error-patterns
  12421   ((error line-start "Error: " (one-or-more not-newline)
  12422           "\n\n  on <stdin> line " line ", in " (one-or-more not-newline) ":"
  12423           (one-or-more "\n" (zero-or-more space (one-or-more not-newline)))
  12424           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
  12425           line-end)
  12426    (error line-start "Error: " (one-or-more not-newline)
  12427           "\n\n  on <stdin> line " line ":\n  (source code not available)\n\n"
  12428           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
  12429           line-end))
  12430   :next-checkers ((warning . terraform-tflint))
  12431   :modes terraform-mode)
  12432 
  12433 (flycheck-def-option-var flycheck-tflint-variable-files nil terraform-tflint
  12434   "A list of files to resolve terraform variables.
  12435 
  12436 The value of this variable is a list of strings, where each
  12437 string is a file to add to the terraform variables files.
  12438 Relative files are relative to the file being checked."
  12439   :type '(repeat (directory :tag "Variable file"))
  12440   :safe #'flycheck-string-list-p
  12441   :package-version '(flycheck . "32"))
  12442 
  12443 (defun flycheck-parse-tflint-linter (output checker buffer)
  12444   "Parse tflint warnings from JSON OUTPUT.
  12445 
  12446 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  12447 the BUFFER that was checked respectively.
  12448 
  12449 See URL `https://github.com/terraform-linters/tflint' for more
  12450 information about tflint."
  12451   (mapcar (lambda (err)
  12452             (let-alist err
  12453               (flycheck-error-new-at
  12454                .range.start.line
  12455                .range.start.column
  12456                (pcase .rule.severity
  12457                  ("error"   'error)
  12458                  ("warning" 'warning)
  12459                  (_         'error))
  12460                .message
  12461                :end-line .range.end.line
  12462                :end-column .range.end.column
  12463                :id .rule.name
  12464                :checker checker
  12465                :buffer buffer
  12466                :filename (buffer-file-name buffer))))
  12467           (cdr (assq 'issues (car (flycheck-parse-json output))))))
  12468 
  12469 (flycheck-define-checker terraform-tflint
  12470   "A Terraform checker using tflint.
  12471 
  12472 See URL `https://github.com/terraform-linters/tflint'."
  12473   :command ("tflint" "--format=json" "--force"
  12474             (option-list "--var-file=" flycheck-tflint-variable-files concat))
  12475   :error-parser flycheck-parse-tflint-linter
  12476   :predicate flycheck-buffer-saved-p
  12477   :modes terraform-mode)
  12478 
  12479 (flycheck-define-checker tex-chktex
  12480   "A TeX and LaTeX syntax and style checker using chktex.
  12481 
  12482 See URL `https://www.nongnu.org/chktex/'."
  12483   :command ("chktex"
  12484             (config-file "--localrc" flycheck-chktexrc)
  12485             ;; Compact error messages, and no version information, and execute
  12486             ;; \input statements
  12487             "--verbosity=0" "--quiet" "--inputfiles")
  12488   :standard-input t
  12489   :error-patterns
  12490   ((warning line-start "stdin:" line ":" column ":"
  12491             (id (one-or-more digit)) ":" (message) line-end))
  12492   :error-filter
  12493   (lambda (errors)
  12494     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
  12495   :modes (latex-mode LaTeX-mode plain-tex-mode plain-TeX-mode))
  12496 
  12497 (flycheck-define-checker tex-lacheck
  12498   "A LaTeX syntax and style checker using lacheck.
  12499 
  12500 See URL `https://www.ctan.org/pkg/lacheck'."
  12501   :command ("lacheck" source-inplace)
  12502   :error-patterns
  12503   ((warning line-start
  12504             "\"" (file-name) "\", line " line ": " (message)
  12505             line-end))
  12506   :modes (latex-mode LaTeX-mode))
  12507 
  12508 (flycheck-define-checker texinfo
  12509   "A Texinfo syntax checker using makeinfo.
  12510 
  12511 See URL `https://www.gnu.org/software/texinfo/'."
  12512   :command ("makeinfo" "-o" null-device "-")
  12513   :standard-input t
  12514   :error-patterns
  12515   ((warning line-start
  12516             "-:" line (optional ":" column) ": " "warning: " (message)
  12517             line-end)
  12518    (error line-start
  12519           "-:" line (optional ":" column) ": " (message)
  12520           line-end))
  12521   :modes (texinfo-mode Texinfo-mode))
  12522 
  12523 (flycheck-def-config-file-var flycheck-textlint-config
  12524     textlint "textlintrc.json")
  12525 
  12526 ;; This needs to be set because textlint plugins are installed separately,
  12527 ;; and there is no way to check their installation status -- textlint simply
  12528 ;; prints a backtrace.
  12529 (flycheck-def-option-var flycheck-textlint-plugin-alist
  12530     '((markdown-mode . "@textlint/markdown")
  12531       (gfm-mode . "@textlint/markdown")
  12532       (t . "@textlint/text"))
  12533     textlint
  12534   "An alist mapping major modes to textlint plugins.
  12535 
  12536 Each item is a cons cell `(MAJOR-MODE . PLUGIN)', where MAJOR-MODE is a mode
  12537 `flycheck-textlint' supports and PLUGIN is a textlint plugin. As a catch-all,
  12538 when MAJOR-MODE is t, that PLUGIN will be used for any supported mode that
  12539 isn't specified.
  12540 
  12541 See URL `https://npms.io/search?q=textlint-plugin' for all textlint plugins
  12542 published on NPM."
  12543   :type '(repeat (choice (cons symbol string)
  12544                          (cons (const t) string))))
  12545 
  12546 (defun flycheck--textlint-get-plugin ()
  12547   "Return the textlint plugin for the current mode."
  12548   (cdr (seq-find
  12549         (lambda (arg)
  12550           (pcase-let ((`(,mode . _) arg))
  12551             (or (and (booleanp mode) mode) ; mode is t
  12552                 (derived-mode-p mode))))
  12553         flycheck-textlint-plugin-alist)))
  12554 
  12555 (flycheck-define-checker textlint
  12556   "A text prose linter using textlint.
  12557 
  12558 See URL `https://textlint.github.io/'."
  12559   :command ("textlint"
  12560             (config-file "--config" flycheck-textlint-config)
  12561             "--format" "json"
  12562             ;; get the first matching plugin from plugin-alist
  12563             "--plugin"
  12564             (eval (flycheck--textlint-get-plugin))
  12565             source)
  12566   ;; textlint seems to say that its json output is compatible with ESLint.
  12567   ;; https://textlint.github.io/docs/formatter.html
  12568   :error-parser flycheck-parse-eslint
  12569   ;; textlint can support different formats with textlint plugins, but
  12570   ;; only text and markdown formats are installed by default. Ask the
  12571   ;; user to add mode->plugin mappings manually in
  12572   ;; `flycheck-textlint-plugin-alist'.
  12573   :modes
  12574   (text-mode markdown-mode gfm-mode message-mode adoc-mode
  12575              mhtml-mode latex-mode LaTeX-mode org-mode rst-mode)
  12576   :enabled
  12577   (lambda () (flycheck--textlint-get-plugin))
  12578   :verify
  12579   (lambda (_)
  12580     (let ((plugin (flycheck--textlint-get-plugin)))
  12581       (list
  12582        (flycheck-verification-result-new
  12583         :label "textlint plugin"
  12584         :message plugin
  12585         :face 'success)))))
  12586 
  12587 (flycheck-def-config-file-var flycheck-typescript-tslint-config
  12588     typescript-tslint "tslint.json"
  12589   :package-version '(flycheck . "27"))
  12590 
  12591 (flycheck-def-option-var flycheck-typescript-tslint-rulesdir
  12592     nil typescript-tslint
  12593   "The directory of custom rules for TSLint.
  12594 
  12595 The value of this variable is either a string containing the path
  12596 to a directory with custom rules, or nil, to not give any custom
  12597 rules to TSLint.
  12598 
  12599 Refer to the TSLint manual at URL
  12600 `https://palantir.github.io/tslint/usage/cli/'
  12601 for more information about the custom directory."
  12602   :type '(choice (const :tag "No custom rules directory" nil)
  12603                  (directory :tag "Custom rules directory"))
  12604   :safe #'flycheck-string-or-nil-p
  12605   :package-version '(flycheck . "27"))
  12606 
  12607 (flycheck-def-args-var flycheck-tslint-args (typescript-tslint)
  12608   :package-version '(flycheck . "31"))
  12609 
  12610 (flycheck-define-checker typescript-tslint
  12611   "TypeScript style checker using TSLint.
  12612 
  12613 Note that this syntax checker is not used if
  12614 `flycheck-typescript-tslint-config' is nil or refers to a
  12615 non-existing file.
  12616 
  12617 See URL `https://github.com/palantir/tslint'."
  12618   :command ("tslint" "--format" "json"
  12619             (config-file "--config" flycheck-typescript-tslint-config)
  12620             (option "--rules-dir" flycheck-typescript-tslint-rulesdir)
  12621             (eval flycheck-tslint-args)
  12622             source-inplace)
  12623   :error-parser flycheck-parse-tslint
  12624   :modes (typescript-mode typescript-ts-mode tsx-ts-mode))
  12625 
  12626 (flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator
  12627   "A list of include directories for Verilator.
  12628 
  12629 The value of this variable is a list of strings, where each
  12630 string is a directory to add to the include path of Verilator.
  12631 Relative paths are relative to the file being checked."
  12632   :type '(repeat (directory :tag "Include directory"))
  12633   :safe #'flycheck-string-list-p
  12634   :package-version '(flycheck . "0.24"))
  12635 
  12636 (flycheck-define-checker verilog-verilator
  12637   "A Verilog syntax checker using the Verilator Verilog HDL simulator.
  12638 
  12639 See URL `https://www.veripool.org/wiki/verilator'."
  12640   :command ("verilator" "--lint-only" "-Wall" "--quiet-exit"
  12641             (option-list "-I" flycheck-verilator-include-path concat)
  12642             source)
  12643   :error-patterns
  12644   ((warning line-start "%Warning"
  12645             (? "-" (id (+ (any "0-9A-Z_")))) ": "
  12646             (? (file-name) ":" line ":" (? column ":") " ")
  12647             (message) line-end)
  12648    (error line-start "%Error"
  12649           (? "-" (id (+ (any "0-9A-Z_")))) ": "
  12650           (? (file-name) ":" line ":" (? column ":") " ")
  12651           (message) line-end))
  12652   :modes verilog-mode)
  12653 
  12654 (flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl
  12655   "The language standard to use in GHDL.
  12656 
  12657 The value of this variable is either a string denoting a language
  12658 standard, or nil, to use the default standard.  When non-nil,
  12659 pass the language standard via the `--std' option."
  12660   :type '(choice (const :tag "Default standard" nil)
  12661                  (string :tag "Language standard"))
  12662   :safe #'flycheck-string-or-nil-p
  12663   :package-version '(flycheck . "32"))
  12664 (make-variable-buffer-local 'flycheck-ghdl-language-standard)
  12665 
  12666 (flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl
  12667   "The directory to use for the file library.
  12668 
  12669 The value of this variable is either a string with the directory
  12670 to use for the file library, or nil, to use the default value.
  12671 When non-nil, pass the directory via the `--workdir' option."
  12672   :type '(choice (const :tag "Default directory" nil)
  12673                  (string :tag "Directory for the file library"))
  12674   :safe #'flycheck-string-or-nil-p
  12675   :package-version '(flycheck . "32"))
  12676 (make-variable-buffer-local 'flycheck-ghdl-workdir)
  12677 
  12678 (flycheck-def-option-var flycheck-ghdl-ieee-library nil vhdl-ghdl
  12679   "The standard to use for the IEEE library.
  12680 
  12681 The value of this variable is either a string denoting an ieee library
  12682 standard, or nil, to use the default standard.  When non-nil,
  12683 pass the ieee library standard via the `--ieee' option."
  12684   :type '(choice (const :tag "Default standard" nil)
  12685                  (const :tag "No IEEE Library" "none")
  12686                  (const :tag "IEEE standard" "standard")
  12687                  (const :tag "Synopsys standard" "synopsys")
  12688                  (const :tag "Mentor standard" "mentor"))
  12689   :safe #'flycheck-string-or-nil-p
  12690   :package-version '(flycheck . "32"))
  12691 (make-variable-buffer-local 'flycheck-ghdl-ieee-library)
  12692 
  12693 (flycheck-define-checker vhdl-ghdl
  12694   "A VHDL syntax checker using GHDL.
  12695 
  12696 See URL `https://github.com/ghdl/ghdl'."
  12697   :command ("ghdl"
  12698             "-s" ; only do the syntax checking
  12699             (option "--std=" flycheck-ghdl-language-standard concat)
  12700             (option "--workdir=" flycheck-ghdl-workdir concat)
  12701             (option "--ieee=" flycheck-ghdl-ieee-library concat)
  12702             source)
  12703   :error-patterns
  12704   ((error line-start (file-name) ":" line ":" column ": " (message) line-end))
  12705   :modes vhdl-mode)
  12706 
  12707 (flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet
  12708   "An XSD schema to validate against."
  12709   :type '(choice (const :tag "None" nil)
  12710                  (file :tag "XSD schema"))
  12711   :safe #'flycheck-string-or-nil-p
  12712   :package-version '(flycheck . "31"))
  12713 
  12714 (flycheck-define-checker xml-xmlstarlet
  12715   "A XML syntax checker and validator using the xmlstarlet utility.
  12716 
  12717 See URL `https://xmlstar.sourceforge.net/'."
  12718   ;; Validate standard input with verbose error messages, and do not dump
  12719   ;; contents to standard output
  12720   :command ("xmlstarlet" "val" "--err" "--quiet"
  12721             (option "--xsd" flycheck-xml-xmlstarlet-xsd-path)
  12722             "-")
  12723   :standard-input t
  12724   :error-patterns
  12725   ((error line-start "-:" line "." column ": " (message) line-end))
  12726   :modes (xml-mode nxml-mode))
  12727 
  12728 (flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint
  12729   "An XSD schema to validate against."
  12730   :type '(choice (const :tag "None" nil)
  12731                  (file :tag "XSD schema"))
  12732   :safe #'flycheck-string-or-nil-p
  12733   :package-version '(flycheck . "31"))
  12734 
  12735 (flycheck-def-option-var flycheck-xml-xmllint-relaxng-path nil xml-xmllint
  12736   "An RELAX NG schema to validate against."
  12737   :type '(choice (const :tag "None" nil)
  12738                  (file :tag "RELAX NG schema"))
  12739   :safe #'flycheck-string-or-nil-p
  12740   :package-version '(flycheck . "34"))
  12741 
  12742 (flycheck-define-checker xml-xmllint
  12743   "A XML syntax checker and validator using the xmllint utility.
  12744 
  12745 The xmllint is part of libxml2, see URL
  12746 `https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home'."
  12747   :command ("xmllint" "--noout"
  12748             (option "--schema" flycheck-xml-xmllint-xsd-path)
  12749             (option "--relaxng" flycheck-xml-xmllint-relaxng-path)
  12750             "-")
  12751   :standard-input t
  12752   :error-patterns
  12753   ((error line-start "-:" line ": " (message) line-end))
  12754   :modes (xml-mode nxml-mode))
  12755 
  12756 (flycheck-define-checker yaml-jsyaml
  12757   "A YAML syntax checker using JS-YAML.
  12758 
  12759 See URL `https://github.com/nodeca/js-yaml'."
  12760   :command ("js-yaml")
  12761   :standard-input t
  12762   :error-patterns
  12763   ((error line-start
  12764           (or "JS-YAML" "YAMLException") ": "
  12765           (message) " at line " line ", column " column ":"
  12766           line-end)
  12767    (error line-start
  12768           (or "JS-YAML" "YAMLException") ": "
  12769           (message) " (" line ":" column ")"
  12770           line-end))
  12771   :modes (yaml-mode yaml-ts-mode)
  12772   :next-checkers ((warning . yaml-yamllint)
  12773                   (warning . cwl)))
  12774 
  12775 (flycheck-define-checker yaml-ruby
  12776   "A YAML syntax checker using Ruby's YAML parser.
  12777 
  12778 This syntax checker uses the YAML parser from Ruby's standard
  12779 library.
  12780 
  12781 See URL `https://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'."
  12782   :command ("ruby" "-ryaml" "-e" "begin;
  12783    YAML.load(STDIN); \
  12784  rescue Exception => e; \
  12785    STDERR.puts \"stdin:#{e}\"; \
  12786  end")
  12787   :standard-input t
  12788   :error-patterns
  12789   ((error line-start "stdin:" (zero-or-more not-newline) ":" (message)
  12790           "at line " line " column " column line-end))
  12791   :modes (yaml-mode yaml-ts-mode)
  12792   :next-checkers ((warning . yaml-yamllint)
  12793                   (warning . cwl)))
  12794 
  12795 (flycheck-def-config-file-var flycheck-yamllintrc
  12796     yaml-yamllint
  12797     '(".yamllint"
  12798       ".yamllint.yaml"
  12799       ".yamllint.yml"
  12800       "~/.config/yamllint/config"))
  12801 
  12802 (flycheck-define-checker yaml-yamllint
  12803   "A YAML syntax checker using YAMLLint.
  12804 See URL `https://github.com/adrienverge/yamllint'."
  12805   :standard-input t
  12806   :command ("yamllint" "-f" "parsable" "-"
  12807             (config-file "-c" flycheck-yamllintrc))
  12808   :error-patterns
  12809   ((error line-start
  12810           "stdin:" line ":" column ": [error] " (message) line-end)
  12811    (warning line-start
  12812             "stdin:" line ":" column ": [warning] " (message) line-end))
  12813   :modes (yaml-mode yaml-ts-mode)
  12814   :next-checkers ((warning . cwl)))
  12815 
  12816 (provide 'flycheck)
  12817 
  12818 ;; Local Variables:
  12819 ;; coding: utf-8
  12820 ;; indent-tabs-mode: nil
  12821 ;; End:
  12822 
  12823 ;;; flycheck.el ends here