config

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

flycheck.el (513939B)


      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 ;; Package-Version: 20241130.1502
     14 ;; Package-Revision: ebaf48359b3e
     15 ;; Package-Requires: ((emacs "26.1"))
     16 
     17 ;; This file is not part of GNU Emacs.
     18 
     19 ;; This program is free software: you can redistribute it and/or modify
     20 ;; it under the terms of the GNU General Public License as published by
     21 ;; the Free Software Foundation, either version 3 of the License, or
     22 ;; (at your option) any later version.
     23 
     24 ;; This program is distributed in the hope that it will be useful,
     25 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     26 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     27 ;; GNU General Public License for more details.
     28 
     29 ;; You should have received a copy of the GNU General Public License
     30 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     31 
     32 ;;; Commentary:
     33 
     34 ;; On-the-fly syntax checking for GNU Emacs.
     35 ;;
     36 ;; Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs,
     37 ;; intended as replacement for the older Flymake extension which is part of GNU
     38 ;; Emacs.
     39 ;;
     40 ;; Flycheck automatically checks buffers for errors while you type, and reports
     41 ;; warnings and errors directly in the buffer and in an optional IDE-like error
     42 ;; list.
     43 ;;
     44 ;; It comes with a rich interface for custom syntax checkers and other
     45 ;; extensions, and has already many 3rd party extensions adding new features.
     46 ;;
     47 ;; Please read the online manual at https://www.flycheck.org for more
     48 ;; information.  You can open the manual directly from Emacs with `M-x
     49 ;; flycheck-manual'.
     50 ;;
     51 ;; # Setup
     52 ;;
     53 ;; Flycheck works best on Unix systems.  It does not officially support Windows,
     54 ;; but tries to maintain Windows compatibility and should generally work fine on
     55 ;; Windows, too.
     56 ;;
     57 ;; To enable Flycheck add the following to your init file:
     58 ;;
     59 ;;    (add-hook 'after-init-hook #'global-flycheck-mode)
     60 ;;
     61 ;; Flycheck will then automatically check buffers in supported languages, as
     62 ;; long as all necessary tools are present.  Use `flycheck-verify-setup' to
     63 ;; troubleshoot your Flycheck setup.
     64 
     65 ;;; Code:
     66 
     67 (eval-when-compile
     68   (require 'let-alist)      ; `let-alist'
     69   (require 'compile)        ; Compile Mode integration
     70   (require 'jka-compr)      ; To inhibit compression of temp files
     71   (require 'pcase)          ; `pcase-dolist' (`pcase' itself is autoloaded)
     72   )
     73 
     74 (require 'seq)                   ; Sequence functions
     75 (require 'subr-x)                ; Additional utilities
     76 (require 'cl-lib)                ; `cl-defstruct' and CL utilities
     77 (require 'tabulated-list)        ; To list errors
     78 (require 'easymenu)              ; Flycheck Mode menu definition
     79 (require 'rx)                    ; Regexp fanciness in `flycheck-define-checker'
     80 (require 'help-mode)             ; `define-button-type'
     81 (require 'find-func)             ; `find-function-regexp-alist'
     82 (require 'json)                  ; `flycheck-parse-json'
     83 (require 'ansi-color)            ; `flycheck-parse-with-patterns-without-color'
     84 
     85 
     86 ;; Declare a bunch of dynamic variables that we need from other modes
     87 (defvar sh-shell)                       ; For shell script checker predicates
     88 (defvar ess-language)                   ; For r-lintr predicate
     89 (defvar markdown-hide-markup)                     ;
     90 (defvar markdown-fontify-code-block-default-mode) ; For rust-error-explainer
     91 (defvar markdown-fontify-code-blocks-natively)    ;
     92 
     93 ;; Tell the byte compiler about autoloaded functions from packages
     94 (declare-function pkg-info-version-info "pkg-info" (package))
     95 
     96 
     97 ;;; Customization
     98 (defgroup flycheck nil
     99   "Modern on-the-fly syntax checking for GNU Emacs."
    100   :prefix "flycheck-"
    101   :group 'tools
    102   :link '(url-link :tag "Website" "https://www.flycheck.org")
    103   :link '(url-link :tag "Github" "https://github.com/flycheck/flycheck"))
    104 
    105 (defgroup flycheck-config-files nil
    106   "Configuration files for on-the-fly syntax checkers."
    107   :prefix "flycheck-"
    108   :group 'flycheck)
    109 
    110 (defgroup flycheck-options nil
    111   "Options for on-the-fly syntax checkers."
    112   :prefix "flycheck-"
    113   :group 'flycheck)
    114 
    115 (defgroup flycheck-executables nil
    116   "Executables of syntax checkers."
    117   :prefix "flycheck-"
    118   :group 'flycheck)
    119 
    120 (defgroup flycheck-faces nil
    121   "Faces used by on-the-fly syntax checking."
    122   :prefix "flycheck-"
    123   :group 'flycheck)
    124 
    125 (defcustom flycheck-checkers
    126   '(ada-gnat
    127     asciidoctor
    128     asciidoc
    129     awk-gawk
    130     bazel-build-buildifier
    131     bazel-module-buildifier
    132     bazel-starlark-buildifier
    133     bazel-workspace-buildifier
    134     c/c++-clang
    135     c/c++-gcc
    136     c/c++-cppcheck
    137     cfengine
    138     coffee
    139     coffee-coffeelint
    140     css-csslint
    141     css-stylelint
    142     cuda-nvcc
    143     cwl
    144     d-dmd
    145     dockerfile-hadolint
    146     elixir-credo
    147     emacs-lisp
    148     emacs-lisp-checkdoc
    149     ember-template
    150     erlang-rebar3
    151     erlang
    152     eruby-erubis
    153     eruby-ruumba
    154     fortran-gfortran
    155     go-gofmt
    156     go-vet
    157     go-build
    158     go-test
    159     go-errcheck
    160     go-unconvert
    161     go-staticcheck
    162     groovy
    163     haml
    164     haml-lint
    165     handlebars
    166     haskell-stack-ghc
    167     haskell-ghc
    168     haskell-hlint
    169     html-tidy
    170     javascript-eslint
    171     javascript-jshint
    172     javascript-standard
    173     json-jsonlint
    174     json-python-json
    175     json-jq
    176     jsonnet
    177     less
    178     less-stylelint
    179     llvm-llc
    180     lua-luacheck
    181     lua
    182     markdown-markdownlint-cli
    183     markdown-mdl
    184     markdown-pymarkdown
    185     nix
    186     nix-linter
    187     opam
    188     perl
    189     perl-perlcritic
    190     perl-perlimports
    191     php
    192     php-phpmd
    193     php-phpcs
    194     php-phpcs-changed
    195     processing
    196     proselint
    197     protobuf-protoc
    198     protobuf-prototool
    199     pug
    200     puppet-parser
    201     puppet-lint
    202     python-flake8
    203     python-ruff
    204     python-pylint
    205     python-pycompile
    206     python-pyright
    207     python-mypy
    208     r-lintr
    209     r
    210     racket
    211     rpm-rpmlint
    212     rst-sphinx
    213     rst
    214     ruby-rubocop
    215     ruby-chef-cookstyle
    216     ruby-standard
    217     ruby-reek
    218     ruby
    219     ruby-jruby
    220     rust-cargo
    221     rust
    222     rust-clippy
    223     salt-lint
    224     scala
    225     scala-scalastyle
    226     scheme-chicken
    227     scss-lint
    228     sass-stylelint
    229     scss-stylelint
    230     sass/scss-sass-lint
    231     sass
    232     scss
    233     sh-bash
    234     sh-posix-dash
    235     sh-posix-bash
    236     sh-zsh
    237     sh-shellcheck
    238     slim
    239     slim-lint
    240     sql-sqlint
    241     statix
    242     systemd-analyze
    243     tcl-nagelfar
    244     terraform
    245     terraform-tflint
    246     tex-chktex
    247     tex-lacheck
    248     texinfo
    249     textlint
    250     typescript-tslint
    251     verilog-verilator
    252     vhdl-ghdl
    253     xml-xmlstarlet
    254     xml-xmllint
    255     yaml-actionlint
    256     yaml-jsyaml
    257     yaml-ruby
    258     yaml-yamllint)
    259   "Syntax checkers available for automatic selection.
    260 
    261 A list of Flycheck syntax checkers to choose from when syntax
    262 checking a buffer.  Flycheck will automatically select a suitable
    263 syntax checker from this list, unless `flycheck-checker' is set,
    264 either directly or with `flycheck-select-checker'.
    265 
    266 You should not need to change this variable normally.  In order
    267 to disable syntax checkers, please use
    268 `flycheck-disabled-checkers'.  This variable is intended for 3rd
    269 party extensions to tell Flycheck about new syntax checkers.
    270 
    271 Syntax checkers in this list must be defined with
    272 `flycheck-define-checker'."
    273   :group 'flycheck
    274   :type '(repeat (symbol :tag "Checker"))
    275   :risky t)
    276 
    277 (defcustom flycheck-disabled-checkers nil
    278   "Syntax checkers excluded from automatic selection.
    279 
    280 A list of Flycheck syntax checkers to exclude from automatic
    281 selection.  Flycheck will never automatically select a syntax
    282 checker in this list, regardless of the value of
    283 `flycheck-checkers'.
    284 
    285 However, syntax checkers in this list are still available for
    286 manual selection with `flycheck-select-checker'.
    287 
    288 Use this variable to disable syntax checkers, instead of removing
    289 the syntax checkers from `flycheck-checkers'.  You may also use
    290 this option as a file or directory local variable to disable
    291 specific checkers in individual files and directories
    292 respectively."
    293   :group 'flycheck
    294   :type '(repeat (symbol :tag "Checker"))
    295   :package-version '(flycheck . "0.16")
    296   :safe #'flycheck-symbol-list-p)
    297 (make-variable-buffer-local 'flycheck-disabled-checkers)
    298 
    299 (defvar-local flycheck--automatically-disabled-checkers nil
    300   "List of syntax checkers automatically disabled for this buffer.
    301 
    302 A checker can be automatically disabled in two cases:
    303 
    304 1. Its `:enabled' predicate returned false.
    305 2. It returned too many errors (see `flycheck-checker-error-threshold').
    306 
    307 To trigger a reverification from Emacs Lisp code, do not modify
    308 this variable: use `flycheck-reset-enabled-checker'.")
    309 
    310 (defvar-local flycheck-checker nil
    311   "Syntax checker to use for the current buffer.
    312 
    313 If unset or nil, automatically select a suitable syntax checker
    314 from `flycheck-checkers' on every syntax check.
    315 
    316 If set to a syntax checker only use this syntax checker and never
    317 select one from `flycheck-checkers' automatically.  The syntax
    318 checker is used regardless of whether it is contained in
    319 `flycheck-checkers' or `flycheck-disabled-checkers'.  If the
    320 syntax checker is unusable in the current buffer an error is
    321 signaled.
    322 
    323 A syntax checker assigned to this variable must be defined with
    324 `flycheck-define-checker'.
    325 
    326 Use the command `flycheck-select-checker' to select a syntax
    327 checker for the current buffer, or set this variable as file
    328 local variable to always use a specific syntax checker for a
    329 file.  See Info Node `(Emacs)Specifying File Variables' for more
    330 information about file variables.")
    331 (put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p)
    332 
    333 (defcustom flycheck-locate-config-file-functions nil
    334   "Functions to locate syntax checker configuration files.
    335 
    336 Each function in this hook must accept two arguments: The value
    337 of the configuration file variable, and the syntax checker
    338 symbol.  It must return either a string with an absolute path to
    339 the configuration file, or nil, if it cannot locate the
    340 configuration file.
    341 
    342 The functions in this hook are called in order of appearance, until a
    343 function returns non-nil.  The configuration file returned by that
    344 function is then given to the syntax checker if it exists.
    345 
    346 This variable is an abnormal hook.  See Info
    347 node `(elisp)Hooks'."
    348   :group 'flycheck
    349   :type 'hook
    350   :risky t)
    351 
    352 (defcustom flycheck-checker-error-threshold 400
    353   "Maximum errors allowed per syntax checker.
    354 
    355 The value of this variable is either an integer denoting the
    356 maximum number of errors per syntax checker and buffer, or nil to
    357 not limit the errors reported from a syntax checker.
    358 
    359 If this variable is a number and a syntax checker reports more
    360 errors than the value of this variable, its errors are not
    361 discarded, and not highlighted in the buffer or available in the
    362 error list.  The affected syntax checker is also disabled for
    363 future syntax checks of the buffer."
    364   :group 'flycheck
    365   :type '(choice (const :tag "Do not limit reported errors" nil)
    366                  (integer :tag "Maximum number of errors"))
    367   :risky t
    368   :package-version '(flycheck . "0.22"))
    369 
    370 (defcustom flycheck-process-error-functions nil
    371   "Functions to process errors.
    372 
    373 Each function in this hook must accept a single argument: A
    374 Flycheck error to process.
    375 
    376 All functions in this hook are called in order of appearance,
    377 until a function returns non-nil.  Thus, a function in this hook
    378 may return nil, to allow for further processing of the error, or
    379 any non-nil value, to indicate that the error was fully processed
    380 and inhibit any further processing.
    381 
    382 The functions are called for each newly parsed error immediately
    383 after the corresponding syntax checker finished.  At this stage,
    384 the overlays from the previous syntax checks are still present,
    385 and there may be further syntax checkers in the chain.
    386 
    387 This variable is an abnormal hook.  See Info
    388 node `(elisp)Hooks'."
    389   :group 'flycheck
    390   :type 'hook
    391   :package-version '(flycheck . "0.13")
    392   :risky t)
    393 
    394 (defcustom flycheck-auto-display-errors-after-checking t
    395   "Whether to automatically display errors at the current point after checking.
    396 
    397 When being set to `nil', it will prevent Flycheck from automatically displaying
    398 error messages. This setting is useful when Flycheck is used together with
    399 `flycheck-posframe', to prevent `flycheck-posframe' from repeatedly displaying
    400 errors at point."
    401   :group 'flycheck
    402   :type 'boolean
    403   :package-version '(flycheck . "35")
    404   :safe #'booleanp)
    405 
    406 (defcustom flycheck-display-errors-delay 0.9
    407   "Delay in seconds before displaying errors at point.
    408 
    409 Use floating point numbers to express fractions of seconds."
    410   :group 'flycheck
    411   :type 'number
    412   :package-version '(flycheck . "0.15")
    413   :safe #'numberp)
    414 
    415 (defcustom flycheck-display-errors-function #'flycheck-display-error-messages
    416   "Function to display error messages.
    417 
    418 If set to a function, call the function with the list of errors
    419 to display as single argument.  Each error is an instance of the
    420 `flycheck-error' struct.
    421 
    422 If set to nil, do not display errors at all."
    423   :group 'flycheck
    424   :type '(choice (const :tag "Display error messages"
    425                         flycheck-display-error-messages)
    426                  (const :tag "Display error messages only if no error list"
    427                         flycheck-display-error-messages-unless-error-list)
    428                  (function :tag "Error display function"))
    429   :package-version '(flycheck . "0.13")
    430   :risky t)
    431 
    432 (defcustom flycheck-clear-displayed-errors-function #'flycheck-clear-displayed-error-messages
    433   "Function to hide error message displayed by `flycheck-display-errors-function'.
    434 
    435 If set to a function, it will be called with no arguments to
    436 clear all displayed errors at point."
    437   :group 'flycheck
    438   :type '(choice (const :tag "Clear displayed error messages"
    439                         flycheck-clear-displayed-error-messages)
    440                  (function :tag "Clear displayed errors function"))
    441   :package-version '(flycheck . "34.2")
    442   :risky t)
    443 
    444 (defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages
    445   "Function to compute the contents of the error tooltips.
    446 
    447 If set to a function, call the function with the list of errors
    448 to display as single argument.  Each error is an instance of the
    449 `flycheck-error' struct.  The function is used to set the
    450 help-echo property of flycheck error overlays.  It should return
    451 a string, which is displayed when the user hovers over an error
    452 or presses \\[display-local-help].
    453 
    454 If set to nil, do not show error tooltips."
    455   :group 'flycheck
    456   :type '(choice (const :tag "Concatenate error messages to form a tooltip"
    457                         flycheck-help-echo-all-error-messages)
    458                  (function :tag "Help echo function"))
    459   :package-version '(flycheck . "0.25")
    460   :risky t)
    461 
    462 (defcustom flycheck-command-wrapper-function #'identity
    463   "Function to modify checker commands before execution.
    464 
    465 The value of this option is a function which is given a list
    466 containing the full command of a syntax checker after
    467 substitution through `flycheck-substitute-argument' but before
    468 execution.  The function may return a new command for Flycheck to
    469 execute.
    470 
    471 The default value is `identity' which does not change the
    472 command.  You may provide your own function to run Flycheck
    473 commands through `bundle exec', `nix-shell' or similar wrappers."
    474   :group 'flycheck
    475   :type '(choice (const :tag "Do not modify commands" identity)
    476                  (function :tag "Modify command with a custom function"))
    477   :package-version '(flycheck . "0.25")
    478   :risky t)
    479 
    480 (defcustom flycheck-executable-find #'flycheck-default-executable-find
    481   "Function to search for executables.
    482 
    483 The value of this option is a function which is given the name or
    484 path of an executable and shall return the full path to the
    485 executable, or nil if the executable does not exit.
    486 
    487 The default is `flycheck-default-executable-find', which searches
    488 variable `exec-path' when given a command name, and resolves
    489 paths to absolute ones.  You can customize this option to search
    490 for checkers in other environments such as bundle or NixOS
    491 sandboxes."
    492   :group 'flycheck
    493   :type '(choice
    494           (const :tag "Search executables in `exec-path'"
    495                  flycheck-default-executable-find)
    496           (function :tag "Search executables with a custom function"))
    497   :package-version '(flycheck . "32")
    498   :risky t)
    499 
    500 (defun flycheck-default-executable-find (executable)
    501   "Resolve EXECUTABLE to a full path.
    502 
    503 Like `executable-find', but supports relative paths.
    504 
    505 Attempts invoking `executable-find' first; if that returns nil,
    506 and EXECUTABLE contains a directory component, expands to a full
    507 path and tries invoking `executable-find' again."
    508   ;; file-name-directory returns non-nil iff the given path has a
    509   ;; directory component.
    510   (or
    511    (executable-find executable)
    512    (when (file-name-directory executable)
    513      (executable-find (expand-file-name executable)))))
    514 
    515 (defcustom flycheck-indication-mode 'left-fringe
    516   "The indication mode for Flycheck errors.
    517 
    518 This variable controls how Flycheck indicates errors in buffers.
    519 May be `left-fringe', `right-fringe', `left-margin',
    520 `right-margin', or nil.
    521 
    522 If set to `left-fringe' or `right-fringe', indicate errors via
    523 icons in the left and right fringe respectively.  If set to
    524 `left-margin' or `right-margin', use the margins instead.
    525 
    526 If set to nil, do not indicate errors and warnings, but just
    527 highlight them according to `flycheck-highlighting-mode'."
    528   :group 'flycheck
    529   :type '(choice (const :tag "Indicate in the left fringe" left-fringe)
    530                  (const :tag "Indicate in the right fringe" right-fringe)
    531                  (const :tag "Indicate in the left margin" left-margin)
    532                  (const :tag "Indicate in the right margin" right-margin)
    533                  (const :tag "Do not indicate" nil))
    534   :safe #'symbolp)
    535 
    536 (defcustom flycheck-highlighting-mode 'symbols
    537   "The highlighting mode for Flycheck errors and warnings.
    538 
    539 The highlighting mode controls how Flycheck highlights errors in
    540 buffers when a checker only reports the starting position of an
    541 error.  The following modes are known:
    542 
    543 `columns'
    544      Highlight a single character.  If the error does not have a column,
    545      highlight the whole line.
    546 
    547 `symbols'
    548      Highlight a full symbol if there is any, otherwise behave like `columns'.
    549      This is the default.
    550 
    551 `sexps'
    552      Highlight a full expression, if there is any, otherwise behave like
    553      `columns'.  Note that this mode can be *very* slow in some major modes.
    554 
    555 `lines'
    556      Highlight the whole line.
    557 
    558 nil
    559      Do not highlight errors at all.  However, errors will still
    560      be reported in the mode line and in error message popups,
    561      and indicated according to `flycheck-indication-mode'."
    562   :group 'flycheck
    563   :type '(choice (const :tag "Highlight columns only" columns)
    564                  (const :tag "Highlight symbols" symbols)
    565                  (const :tag "Highlight expressions" sexps)
    566                  (const :tag "Highlight whole lines" lines)
    567                  (const :tag "Do not highlight errors" nil))
    568   :package-version '(flycheck . "0.14")
    569   :safe #'symbolp)
    570 
    571 (defvar flycheck-current-errors)
    572 (defun flycheck-refresh-fringes-and-margins ()
    573   "Refresh fringes and margins of all windows displaying the current buffer.
    574 
    575 If any errors are currently shown, launch a new check, to adjust
    576 to a potential new indication mode."
    577   (dolist (win (get-buffer-window-list))
    578     (set-window-margins win left-margin-width right-margin-width)
    579     (set-window-fringes win left-fringe-width right-fringe-width))
    580   (when flycheck-current-errors
    581     (flycheck-buffer)))
    582 
    583 (defun flycheck-set-indication-mode (&optional mode)
    584   "Set `flycheck-indication-mode' to MODE and adjust margins and fringes.
    585 
    586 When MODE is nil, adjust window parameters without changing the
    587 mode.  This function can be useful as a `flycheck-mode-hook',
    588 especially if you use margins only in Flycheck buffers.
    589 
    590 When MODE is `left-margin', the left fringe is reduced to 1 pixel
    591 to save space."
    592   (interactive (list (intern (completing-read
    593                               "Mode: " '("left-fringe" "right-fringe"
    594                                          "left-margin" "right-margin")
    595                               nil t nil nil
    596                               (prin1-to-string flycheck-indication-mode)))))
    597   (setq mode (or mode flycheck-indication-mode))
    598   (pcase mode
    599     ((or `left-fringe `right-fringe)
    600      (setq left-fringe-width 8 right-fringe-width 8
    601            left-margin-width 0 right-margin-width 0))
    602     (`left-margin
    603      (setq left-fringe-width 1 right-fringe-width 8
    604            left-margin-width 1 right-margin-width 0))
    605     (`right-margin
    606      (setq left-fringe-width 8 right-fringe-width 8
    607            left-margin-width 0 right-margin-width 1))
    608     (_ (user-error "Invalid indication mode")))
    609   (setq-local flycheck-indication-mode mode)
    610   (flycheck-refresh-fringes-and-margins))
    611 
    612 (define-widget 'flycheck-highlighting-style 'lazy
    613   "A value for `flycheck-highlighting-style'."
    614   :offset 2
    615   :format "%t: Use %v"
    616   :type '(choice
    617           :format "%[Value Menu%] %v"
    618           (const :tag "no highlighting" nil)
    619           (const :tag "a face indicating the error level" level-face)
    620           (list :tag "a pair of delimiters"
    621                 (const :format "" delimiters)
    622                 (string :tag "Before")
    623                 (string :tag "After"))
    624           (list :tag "a conditional mix of styles"
    625                 (const :format "" conditional)
    626                 (integer :tag "Up to this many lines")
    627                 (flycheck-highlighting-style :format "Use %v")
    628                 (flycheck-highlighting-style :format "Otherwise, use %v"))))
    629 
    630 (defun flycheck--make-highlighting-delimiter (char)
    631   "Make a highlighting bracket symbol by repeating CHAR twice."
    632   (compose-chars ?\s
    633                  ;; '(Bl . Br) ?\s
    634                  '(Bc Br 30 0) char
    635                  '(Bc Bl -30 0) char))
    636 
    637 (defcustom flycheck-highlighting-style
    638   `(conditional 4 level-face (delimiters "" ""))
    639   "The highlighting style for Flycheck errors and warnings.
    640 
    641 The highlighting style controls how Flycheck highlights error
    642 regions in buffers.  The following styles are supported:
    643 
    644 nil
    645      Do not highlight errors.  Same as setting
    646      `flycheck-highlighting-mode' to nil.
    647 
    648 `level-face'
    649      Chose a face depending on the severity of the error, and
    650      apply it to the whole error text.  See also the
    651      `flycheck-define-error-level' and `flycheck-error',
    652      `flycheck-warning', and `flycheck-info' faces.
    653 
    654 \(`delimiters' BEFORE AFTER)
    655      Draw delimiters on each side of the error.  BEFORE and AFTER
    656      indicate which delimiters to use.  If they are strings, they
    657      are used as-is.  If they are characters, they are repeated
    658      twice and composed into a single character.  Delimiters use
    659      the fringe face corresponding to the severity of each error,
    660      as well as the `flycheck-error-delimiter' face.  Delimited
    661      text has the `flycheck-delimited-error' face.
    662 
    663 \(`conditional' NLINES S1 S2)
    664      Use style S1 for errors spanning up to NLINES lines, and
    665      style S2 otherwise.
    666 
    667 See also `flycheck-highlighting-mode' and
    668 `flycheck-indication-mode'."
    669   :group 'flycheck
    670   :type 'flycheck-highlighting-style
    671   :package-version '(flycheck . "32")
    672   :safe t)
    673 
    674 (defcustom flycheck-check-syntax-automatically '(save
    675                                                  idle-change
    676                                                  new-line
    677                                                  mode-enabled)
    678   "When Flycheck should check syntax automatically.
    679 
    680 This variable is a list of events that may trigger syntax checks.
    681 The following events are known:
    682 
    683 `save'
    684      Check syntax immediately after the buffer was saved.
    685 
    686 `idle-change'
    687      Check syntax a short time (see `flycheck-idle-change-delay')
    688      after the last change to the buffer.
    689 
    690 `idle-buffer-switch'
    691      Check syntax a short time (see `flycheck-idle-buffer-switch-delay')
    692      after the user switches to a buffer.
    693 
    694 `new-line'
    695      Check syntax immediately after a new line was inserted into
    696      the buffer.
    697 
    698 `mode-enabled'
    699      Check syntax immediately when variable `flycheck-mode' is
    700      non-nil.
    701 
    702 Flycheck performs a syntax checks only on events, which are
    703 contained in this list.  For instance, if the value of this
    704 variable is `(mode-enabled save)', Flycheck will only check if
    705 the mode is enabled or the buffer was saved, but never after
    706 changes to the buffer contents.
    707 
    708 If nil, never check syntax automatically.  In this case, use
    709 `flycheck-buffer' to start a syntax check manually."
    710   :group 'flycheck
    711   :type '(set (const :tag "After the buffer was saved" save)
    712               (const :tag "After the buffer was changed and idle" idle-change)
    713               (const
    714                :tag "After switching the current buffer" idle-buffer-switch)
    715               (const :tag "After a new line was inserted" new-line)
    716               (const :tag "After `flycheck-mode' was enabled" mode-enabled))
    717   :package-version '(flycheck . "0.12")
    718   :safe #'flycheck-symbol-list-p)
    719 
    720 (defcustom flycheck-idle-change-delay 0.5
    721   "How many seconds to wait after a change before checking syntax.
    722 
    723 After the buffer was changed, Flycheck will wait as many seconds
    724 as the value of this variable before starting a syntax check.  If
    725 the buffer is modified during this time, Flycheck will wait
    726 again.
    727 
    728 This variable has no effect, if `idle-change' is not contained in
    729 `flycheck-check-syntax-automatically'."
    730   :group 'flycheck
    731   :type 'number
    732   :package-version '(flycheck . "0.13")
    733   :safe #'numberp)
    734 
    735 (defcustom flycheck-idle-buffer-switch-delay 0.5
    736   "How many seconds to wait after switching buffers before checking syntax.
    737 
    738 After the user switches to a new buffer, Flycheck will wait as
    739 many seconds as the value of this variable before starting a
    740 syntax check.  If the user switches to another buffer during this
    741 time, whether a syntax check is still performed depends on the
    742 value of `flycheck-buffer-switch-check-intermediate-buffers'.
    743 
    744 This variable has no effect if `idle-buffer-switch' is not
    745 contained in `flycheck-check-syntax-automatically'."
    746   :group 'flycheck
    747   :type 'number
    748   :package-version '(flycheck . "32")
    749   :safe #'numberp)
    750 
    751 (defcustom flycheck-buffer-switch-check-intermediate-buffers nil
    752   "Whether to check syntax in a buffer you only visit briefly.
    753 
    754 If nil, then when you switch to a buffer but switch to another
    755 buffer before the syntax check is performed, then the check is
    756 canceled.  If non-nil, then syntax checks due to switching
    757 buffers are always performed.  This only affects buffer switches
    758 that happen less than `flycheck-idle-buffer-switch-delay' seconds
    759 apart.
    760 
    761 This variable has no effect if `idle-buffer-switch' is not
    762 contained in `flycheck-check-syntax-automatically'."
    763   :group 'flycheck
    764   :type 'boolean
    765   :package-version '(flycheck . "32")
    766   :safe #'booleanp)
    767 
    768 (defcustom flycheck-standard-error-navigation t
    769   "Whether to support error navigation with `next-error'.
    770 
    771 If non-nil, enable navigation of Flycheck errors with
    772 `next-error', `previous-error' and `first-error'.  Otherwise,
    773 these functions just navigate errors from compilation modes.
    774 
    775 Flycheck error navigation with `flycheck-next-error',
    776 `flycheck-previous-error' and `flycheck-first-error' is always
    777 enabled, regardless of the value of this variable.
    778 
    779 Note that this setting only takes effect when variable
    780 `flycheck-mode' is non-nil.  Changing it will not affect buffers
    781 where variable `flycheck-mode' is already non-nil."
    782   :group 'flycheck
    783   :type 'boolean
    784   :package-version '(flycheck . "0.15")
    785   :safe #'booleanp)
    786 
    787 (define-widget 'flycheck-minimum-level 'lazy
    788   "A radio-type choice of minimum error levels.
    789 
    790 See `flycheck-navigation-minimum-level' and
    791 `flycheck-error-list-minimum-level'."
    792   :type '(radio (const :tag "All locations" nil)
    793                 (const :tag "Informational messages" info)
    794                 (const :tag "Warnings" warning)
    795                 (const :tag "Errors" error)
    796                 (symbol :tag "Custom error level")))
    797 
    798 (defcustom flycheck-navigation-minimum-level nil
    799   "The minimum level of errors to navigate.
    800 
    801 If set to an error level, only navigate errors whose error level
    802 is at least as severe as this one.  If nil, navigate all errors."
    803   :group 'flycheck
    804   :type 'flycheck-minimum-level
    805   :safe #'flycheck-error-level-p
    806   :package-version '(flycheck . "0.21"))
    807 
    808 (defcustom flycheck-error-list-minimum-level nil
    809   "The minimum level of errors to display in the error list.
    810 
    811 If set to an error level, only display errors whose error level
    812 is at least as severe as this one in the error list.  If nil,
    813 display all errors.
    814 
    815 This is the default level, used when the error list is opened.
    816 You can temporarily change the level using
    817 \\[flycheck-error-list-set-filter], or reset it to this value
    818 using \\[flycheck-error-list-reset-filter]."
    819   :group 'flycheck
    820   :type 'flycheck-minimum-level
    821   :safe #'flycheck-error-level-p
    822   :package-version '(flycheck . "0.24"))
    823 
    824 (defcustom flycheck-relevant-error-other-file-minimum-level 'error
    825   "The minimum level of errors from other files to display in this buffer.
    826 
    827 If set to an error level, only display errors from other files
    828 whose error level is at least as severe as this one.  If nil,
    829 display all errors from other files."
    830   :group 'flycheck
    831   :type 'flycheck-minimum-level
    832   :safe #'flycheck-error-level-p
    833   :package-version '(flycheck . "32"))
    834 
    835 (defcustom flycheck-relevant-error-other-file-show t
    836   "Whether to show errors from other files."
    837   :group 'flycheck
    838   :type 'boolean
    839   :package-version '(flycheck . "32")
    840   :safe #'booleanp)
    841 
    842 (defcustom flycheck-completing-read-function #'completing-read
    843   "Function to read from minibuffer with completion.
    844 
    845 The function must be compatible to the built-in `completing-read'
    846 function."
    847   :group 'flycheck
    848   :type '(choice (const :tag "Default" completing-read)
    849                  (const :tag "IDO" ido-completing-read)
    850                  (function :tag "Custom function"))
    851   :risky t
    852   :package-version '(flycheck . "26"))
    853 
    854 (defcustom flycheck-temp-prefix "flycheck"
    855   "Prefix for temporary files created by Flycheck."
    856   :group 'flycheck
    857   :type 'string
    858   :package-version '(flycheck . "0.19")
    859   :risky t)
    860 
    861 (defcustom flycheck-mode-hook nil
    862   "Hooks to run after command `flycheck-mode' is toggled."
    863   :group 'flycheck
    864   :type 'hook
    865   :risky t)
    866 
    867 (defcustom flycheck-after-syntax-check-hook nil
    868   "Functions to run after each syntax check.
    869 
    870 This hook is run after a syntax check was finished.
    871 
    872 At this point, *all* chained checkers were run, and all errors
    873 were parsed, highlighted and reported.  The variable
    874 `flycheck-current-errors' contains all errors from all syntax
    875 checkers run during the syntax check, so you can apply any error
    876 analysis functions.
    877 
    878 Note that this hook does *not* run after each individual syntax
    879 checker in the syntax checker chain, but only after the *last
    880 checker*.
    881 
    882 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    883   :group 'flycheck
    884   :type 'hook
    885   :risky t)
    886 
    887 (defcustom flycheck-before-syntax-check-hook nil
    888   "Functions to run before each syntax check.
    889 
    890 This hook is run right before a syntax check starts.
    891 
    892 Error information from the previous syntax check is *not*
    893 cleared before this hook runs.
    894 
    895 Note that this hook does *not* run before each individual syntax
    896 checker in the syntax checker chain, but only before the *first
    897 checker*.
    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-syntax-check-failed-hook nil
    905   "Functions to run if a syntax check failed.
    906 
    907 This hook is run whenever an error occurs during Flycheck's
    908 internal processing.  No information about the error is given to
    909 this hook.
    910 
    911 You should use this hook to conduct additional cleanup actions
    912 when Flycheck failed.
    913 
    914 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    915   :group 'flycheck
    916   :type 'hook
    917   :risky t)
    918 
    919 (defcustom flycheck-status-changed-functions nil
    920   "Functions to run if the Flycheck status changed.
    921 
    922 This hook is run whenever the status of Flycheck changes.  Each
    923 hook function takes the status symbol as single argument, as
    924 given to `flycheck-report-status', which see.
    925 
    926 This variable is an abnormal hook.  See Info
    927 node `(elisp)Hooks'."
    928   :group 'flycheck
    929   :type 'hook
    930   :risky t
    931   :package-version '(flycheck . "0.20"))
    932 
    933 (defcustom flycheck-error-list-after-refresh-hook nil
    934   "Functions to run after the error list was refreshed.
    935 
    936 This hook is run whenever the error list is refreshed.
    937 
    938 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    939   :group 'flycheck
    940   :type 'hook
    941   :risky t
    942   :package-version '(flycheck . "0.21"))
    943 
    944 (defface flycheck-error-delimiter
    945   `((t))
    946   "Flycheck face for errors spanning multiple lines.
    947 
    948 See `flycheck-highlighting-style' for details on when this face
    949 is used."
    950   :package-version '(flycheck . "32")
    951   :group 'flycheck-faces)
    952 
    953 (defface flycheck-delimited-error
    954   `((t))
    955   "Flycheck face for errors spanning multiple lines.
    956 
    957 See `flycheck-highlighting-style' for details on when this face
    958 is used."
    959   :package-version '(flycheck . "32")
    960   :group 'flycheck-faces)
    961 
    962 (defface flycheck-error
    963   '((((supports :underline (:style wave)))
    964      :underline (:style wave :color "Red1"))
    965     (t
    966      :underline t :inherit error))
    967   "Flycheck face for errors."
    968   :package-version '(flycheck . "0.13")
    969   :group 'flycheck-faces)
    970 
    971 (defface flycheck-warning
    972   '((((supports :underline (:style wave)))
    973      :underline (:style wave :color "DarkOrange"))
    974     (t
    975      :underline t :inherit warning))
    976   "Flycheck face for warnings."
    977   :package-version '(flycheck . "0.13")
    978   :group 'flycheck-faces)
    979 
    980 (defface flycheck-info
    981   '((((supports :underline (:style wave)))
    982      :underline (:style wave :color "ForestGreen"))
    983     (t
    984      :underline t :inherit success))
    985   "Flycheck face for informational messages."
    986   :package-version '(flycheck . "0.15")
    987   :group 'flycheck-faces)
    988 
    989 (defface flycheck-fringe-error
    990   '((t :inherit error))
    991   "Flycheck face for fringe error indicators."
    992   :package-version '(flycheck . "0.13")
    993   :group 'flycheck-faces)
    994 
    995 (defface flycheck-fringe-warning
    996   '((t :inherit warning))
    997   "Flycheck face for fringe warning indicators."
    998   :package-version '(flycheck . "0.13")
    999   :group 'flycheck-faces)
   1000 
   1001 (defface flycheck-fringe-info
   1002   ;; Semantically `success' is probably not the right face, but it looks nice as
   1003   ;; a base face
   1004   '((t :inherit success))
   1005   "Flycheck face for fringe info indicators."
   1006   :package-version '(flycheck . "0.15")
   1007   :group 'flycheck-faces)
   1008 
   1009 (defface flycheck-error-list-error
   1010   '((t :inherit error))
   1011   "Flycheck face for error messages in the error list."
   1012   :package-version '(flycheck . "0.16")
   1013   :group 'flycheck-faces)
   1014 
   1015 (defface flycheck-error-list-warning
   1016   '((t :inherit warning))
   1017   "Flycheck face for warning messages in the error list."
   1018   :package-version '(flycheck . "0.16")
   1019   :group 'flycheck-faces)
   1020 
   1021 (defface flycheck-error-list-info
   1022   '((t :inherit success))
   1023   "Flycheck face for info messages in the error list."
   1024   :package-version '(flycheck . "0.16")
   1025   :group 'flycheck-faces)
   1026 
   1027 (defface flycheck-error-list-line-number
   1028   '((t))
   1029   "Face for line numbers in the error list."
   1030   :group 'flycheck-faces
   1031   :package-version '(flycheck . "0.16"))
   1032 
   1033 (defface flycheck-error-list-column-number
   1034   '((t))
   1035   "Face for line numbers in the error list."
   1036   :group 'flycheck-faces
   1037   :package-version '(flycheck . "0.16"))
   1038 
   1039 (defface flycheck-error-list-filename
   1040   '((t :inherit mode-line-buffer-id :bold nil))
   1041   "Face for filenames in the error list."
   1042   :group 'flycheck-faces
   1043   :package-version '(flycheck . "32"))
   1044 
   1045 (defface flycheck-error-list-id
   1046   '((t :inherit font-lock-type-face))
   1047   "Face for the error ID in the error list."
   1048   :group 'flycheck-faces
   1049   :package-version '(flycheck . "0.22"))
   1050 
   1051 (defface flycheck-error-list-id-with-explainer
   1052   '((t :inherit flycheck-error-list-id
   1053        :box (:style released-button)))
   1054   "Face for the error ID in the error list, for errors that have an explainer."
   1055   :group 'flycheck-faces
   1056   :package-version '(flycheck . "30"))
   1057 
   1058 (defface flycheck-error-list-checker-name
   1059   '((t :inherit font-lock-function-name-face))
   1060   "Face for the syntax checker name in the error list."
   1061   :group 'flycheck-faces
   1062   :package-version '(flycheck . "0.21"))
   1063 
   1064 (defface flycheck-error-list-error-message
   1065   '((t))
   1066   "Face for the error message in the error list."
   1067   :group 'flycheck-faces
   1068   :package-version '(flycheck . "33"))
   1069 
   1070 (defface flycheck-error-list-highlight
   1071   '((t :bold t))
   1072   "Flycheck face to highlight errors in the error list."
   1073   :package-version '(flycheck . "0.15")
   1074   :group 'flycheck-faces)
   1075 
   1076 (defface flycheck-verify-select-checker
   1077   '((t :box (:style released-button)))
   1078   "Flycheck face for the `select' button in the verify setup buffer."
   1079   :package-version '(flycheck . "32")
   1080   :group 'flycheck-faces)
   1081 
   1082 (defvar flycheck-command-map
   1083   (let ((map (make-sparse-keymap)))
   1084     (define-key map "c"         #'flycheck-buffer)
   1085     (define-key map "C"         #'flycheck-clear)
   1086     (define-key map (kbd "C-c") #'flycheck-compile)
   1087     (define-key map "n"         #'flycheck-next-error)
   1088     (define-key map "p"         #'flycheck-previous-error)
   1089     (define-key map "l"         #'flycheck-list-errors)
   1090     (define-key map (kbd "C-w") #'flycheck-copy-errors-as-kill)
   1091     (define-key map "s"         #'flycheck-select-checker)
   1092     (define-key map "?"         #'flycheck-describe-checker)
   1093     (define-key map "h"         #'flycheck-display-error-at-point)
   1094     (define-key map "e"         #'flycheck-explain-error-at-point)
   1095     (define-key map "H"         #'display-local-help)
   1096     (define-key map "i"         #'flycheck-manual)
   1097     (define-key map "V"         #'flycheck-version)
   1098     (define-key map "v"         #'flycheck-verify-setup)
   1099     (define-key map "x"         #'flycheck-disable-checker)
   1100     map)
   1101   "Keymap of Flycheck interactive commands.")
   1102 
   1103 (defcustom flycheck-keymap-prefix (kbd "C-c !")
   1104   "Prefix for key bindings of Flycheck.
   1105 
   1106 Changing this variable outside Customize does not have any
   1107 effect.  To change the keymap prefix from Lisp, you need to
   1108 explicitly re-define the prefix key:
   1109 
   1110     (define-key flycheck-mode-map flycheck-keymap-prefix nil)
   1111     (setq flycheck-keymap-prefix (kbd \"C-c f\"))
   1112     (define-key flycheck-mode-map flycheck-keymap-prefix
   1113                 flycheck-command-map)
   1114 
   1115 Please note that Flycheck's manual documents the default
   1116 keybindings.  Changing this variable is at your own risk."
   1117   :group 'flycheck
   1118   :package-version '(flycheck . "0.19")
   1119   :type 'string
   1120   :risky t
   1121   :set
   1122   (lambda (variable key)
   1123     (when (and (boundp variable) (boundp 'flycheck-mode-map))
   1124       (define-key flycheck-mode-map (symbol-value variable) nil)
   1125       (define-key flycheck-mode-map key flycheck-command-map))
   1126     (set-default variable key)))
   1127 
   1128 (defcustom flycheck-mode-line '(:eval (flycheck-mode-line-status-text))
   1129   "Mode line lighter for Flycheck.
   1130 
   1131 The value of this variable is a mode line template as in
   1132 `mode-line-format'.  See Info Node `(elisp)Mode Line Format' for
   1133 more information.  Note that it should contain a _single_ mode
   1134 line construct only.
   1135 
   1136 Customize this variable to change how Flycheck reports its status
   1137 in the mode line.  You may use `flycheck-mode-line-status-text'
   1138 to obtain a human-readable status text, including an
   1139 error/warning count.
   1140 
   1141 You may also assemble your own status text.  The current status
   1142 of Flycheck is available in `flycheck-last-status-change'.  The
   1143 errors in the current buffer are stored in
   1144 `flycheck-current-errors', and the function
   1145 `flycheck-count-errors' may be used to obtain the number of
   1146 errors grouped by error level.
   1147 
   1148 Set this variable to nil to disable the mode line completely."
   1149   :group 'flycheck
   1150   :type 'sexp
   1151   :risky t
   1152   :package-version '(flycheck . "0.20"))
   1153 
   1154 (defcustom flycheck-mode-line-color t
   1155   "Use colors for Flycheck mode line status."
   1156   :group 'flycheck
   1157   :type 'boolean
   1158   :package-version '(flycheck . "35"))
   1159 
   1160 (defcustom flycheck-mode-line-prefix "FlyC"
   1161   "Base mode line lighter for Flycheck.
   1162 
   1163 This will have an effect only with the default
   1164 `flycheck-mode-line'.
   1165 
   1166 If you've customized `flycheck-mode-line' then the customized
   1167 function must be updated to use this variable."
   1168   :group 'flycheck
   1169   :type 'string
   1170   :package-version '(flycheck . "26"))
   1171 
   1172 (defcustom flycheck-mode-success-indicator ":0"
   1173   "Success indicator appended to `flycheck-mode-line-prefix'."
   1174   :group 'flycheck
   1175   :type 'string
   1176   :package-version '(flycheck . "35"))
   1177 
   1178 (defcustom flycheck-error-list-mode-line
   1179   `(,(propertized-buffer-identification "%12b")
   1180     " for buffer "
   1181     (:eval (flycheck-error-list-propertized-source-name))
   1182     (:eval (flycheck-error-list-mode-line-filter-indicator)))
   1183   "Mode line construct for Flycheck error list.
   1184 
   1185 The value of this variable is a mode line template as in
   1186 `mode-line-format', to be used as
   1187 `mode-line-buffer-identification' in `flycheck-error-list-mode'.
   1188 See Info Node `(elisp)Mode Line Format' for more information.
   1189 
   1190 Customize this variable to change how the error list appears in
   1191 the mode line.  The default shows the name of the buffer and the
   1192 name of the source buffer, i.e. the buffer whose errors are
   1193 currently listed."
   1194   :group 'flycheck
   1195   :type 'sexp
   1196   :risky t
   1197   :package-version '(flycheck . "0.20"))
   1198 
   1199 (defcustom flycheck-global-modes t
   1200   "Modes for which option `flycheck-mode' is turned on.
   1201 
   1202 If t, Flycheck Mode is turned on for all major modes.  If a list,
   1203 Flycheck Mode is turned on for all `major-mode' symbols in that
   1204 list.  If the `car' of the list is `not', Flycheck Mode is turned
   1205 on for all `major-mode' symbols _not_ in that list.  If nil,
   1206 Flycheck Mode is never turned on by command
   1207 `global-flycheck-mode'.
   1208 
   1209 Note that Flycheck is never turned on for modes whose
   1210 `mode-class' property is `special' (see Info node `(elisp)Major
   1211 Mode Conventions'), regardless of the value of this option.
   1212 
   1213 Only has effect when variable `global-flycheck-mode' is non-nil."
   1214   :group 'flycheck
   1215   :type '(choice (const :tag "none" nil)
   1216                  (const :tag "all" t)
   1217                  (set :menu-tag "mode specific" :tag "modes"
   1218                       :value (not)
   1219                       (const :tag "Except" not)
   1220                       (repeat :inline t (symbol :tag "mode"))))
   1221   :risky t
   1222   :package-version '(flycheck . "0.23"))
   1223 
   1224 ;; Add built-in functions to our hooks, via `add-hook', to make sure that our
   1225 ;; functions are really present, even if the variable was implicitly defined by
   1226 ;; another call to `add-hook' that occurred before Flycheck was loaded.  See
   1227 ;; https://lists.gnu.org/archive/html/emacs-devel/2015-02/msg01271.html for why
   1228 ;; we don't initialize the hook variables right away.  We append our own
   1229 ;; functions, because a user likely expects that their functions come first,
   1230 ;; even if they added them before Flycheck was loaded.
   1231 (dolist (hook (list #'flycheck-locate-config-file-by-path
   1232                     #'flycheck-locate-config-file-ancestor-directories
   1233                     #'flycheck-locate-config-file-home))
   1234   (add-hook 'flycheck-locate-config-file-functions hook 'append))
   1235 
   1236 (add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append)
   1237 
   1238 
   1239 ;;; Global Flycheck menu
   1240 (defvar flycheck-mode-menu-map
   1241   (easy-menu-create-menu
   1242    "Syntax Checking"
   1243    '(["Enable on-the-fly syntax checking" flycheck-mode
   1244       :style toggle :selected flycheck-mode
   1245       :enable (or flycheck-mode
   1246                   ;; Don't let users toggle the mode if there is no syntax
   1247                   ;; checker for this buffer
   1248                   (seq-find #'flycheck-checker-supports-major-mode-p
   1249                             flycheck-checkers))]
   1250      ["Check current buffer" flycheck-buffer flycheck-mode]
   1251      ["Clear errors in buffer" flycheck-clear t]
   1252      ["Run checker as compile command" flycheck-compile flycheck-mode]
   1253      "---"
   1254      ["Go to next error" flycheck-next-error flycheck-mode]
   1255      ["Go to previous error" flycheck-previous-error flycheck-mode]
   1256      ["Show all errors" flycheck-list-errors flycheck-mode]
   1257      "---"
   1258      ["Copy messages at point" flycheck-copy-errors-as-kill
   1259       (flycheck-overlays-at (point))]
   1260      ["Explain error at point" flycheck-explain-error-at-point]
   1261      "---"
   1262      ["Select syntax checker" flycheck-select-checker flycheck-mode]
   1263      ["Disable syntax checker" flycheck-disable-checker flycheck-mode]
   1264      ["Set executable of syntax checker" flycheck-set-checker-executable
   1265       flycheck-mode]
   1266      "---"
   1267      ["Describe syntax checker" flycheck-describe-checker t]
   1268      ["Verify setup" flycheck-verify-setup t]
   1269      ["Show Flycheck version" flycheck-version t]
   1270      ["Flycheck quick help" flycheck-quick-help t]
   1271      ["Read the Flycheck manual" flycheck-manual t]))
   1272   "Menu of command `flycheck-mode'.")
   1273 
   1274 (easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking")
   1275 
   1276 
   1277 
   1278 (defconst flycheck-version "35.0-snapshot"
   1279   "The current version of Flycheck.
   1280 
   1281 Should be kept in sync with the package version metadata.
   1282 Used only when `package-get-function' is not available
   1283 or fails.")
   1284 
   1285 (defun flycheck--pkg-version ()
   1286   "Extract FLYCHECK's package version from its package metadata."
   1287   ;; Use `cond' below to avoid a compiler unused return value warning
   1288   ;; when `package-get-version' returns nil. See #3181.
   1289   (cond ((fboundp 'package-get-version)
   1290          (package-get-version))
   1291         ((fboundp 'pkg-info-version-info)
   1292          (pkg-info-version-info 'flycheck))
   1293         (t
   1294          flycheck-version)))
   1295 
   1296 ;;; Version information, manual and loading of Flycheck
   1297 (defun flycheck-version (&optional show-version)
   1298   "Get the Flycheck version as string.
   1299 
   1300 If called interactively or if SHOW-VERSION is non-nil, show the
   1301 version in the echo area and the messages buffer.
   1302 
   1303 The returned string includes both, the version from package.el
   1304 and the library version, if both a present and different.
   1305 
   1306 If the version number could not be determined, signal an error,
   1307 if called interactively, or if SHOW-VERSION is non-nil, otherwise
   1308 just return nil."
   1309   (interactive (list t))
   1310   (let ((version (flycheck--pkg-version)))
   1311     (when show-version
   1312       (message "Flycheck version: %s" version))
   1313     version))
   1314 
   1315 (defun flycheck-unload-function ()
   1316   "Unload function for Flycheck."
   1317   (global-flycheck-mode -1)
   1318   (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map))
   1319   (remove-hook 'kill-emacs-hook #'flycheck-global-teardown)
   1320   (setq find-function-regexp-alist
   1321         (assq-delete-all 'flycheck-checker find-function-regexp-alist)))
   1322 
   1323 ;;;###autoload
   1324 (defun flycheck-manual ()
   1325   "Open the Flycheck manual."
   1326   (interactive)
   1327   (browse-url "https://www.flycheck.org"))
   1328 
   1329 ;;;###autoload
   1330 (defun flycheck-quick-help ()
   1331   "Display brief Flycheck help."
   1332   (interactive)
   1333   (with-current-buffer (get-buffer-create "*flycheck-quick-help*")
   1334     (with-help-window (current-buffer)
   1335       (flycheck-mode) ;; so that we can exapnd \\[flycheck-<function>]
   1336       (let ((help
   1337              (substitute-command-keys
   1338         "Flycheck automatically runs checks on writable files when changed.
   1339 Mode line status for the current buffer:
   1340   FlyC        Not been checked yet
   1341   FlyC*       Flycheck is running
   1342   FlyC:0      Last check resulted in no errors and no warnings
   1343   FlyC:3|5    Checker reported three errors and five warnings
   1344   FlyC-       No checker available
   1345   FlyC!       The checker crashed
   1346   FlyC.       The last syntax check was manually interrupted
   1347   FlyC?       The checker did something unexpected
   1348 
   1349 Key bindings:
   1350   \\[flycheck-buffer]     Check current buffer
   1351   \\[flycheck-clear]     Clear errors in current buffer
   1352   \\[flycheck-compile]   Run checker as compile command
   1353 
   1354   \\[flycheck-next-error]     Next error
   1355   \\[flycheck-previous-error]     Previous error
   1356   \\[flycheck-list-errors]     List all errors
   1357 
   1358   \\[flycheck-copy-errors-as-kill]   Copy error messages at point
   1359   \\[flycheck-display-error-at-point]     Explain error at point
   1360 ")))
   1361         (help-mode)
   1362         (read-only-mode 0)
   1363         (insert help)))))
   1364 
   1365 (define-obsolete-function-alias 'flycheck-info
   1366   'flycheck-manual "Flycheck 26" "Open the Flycheck manual.")
   1367 
   1368 
   1369 ;;; Utility functions
   1370 (defun flycheck-sexp-to-string (sexp)
   1371   "Convert SEXP to a string.
   1372 
   1373 Like `prin1-to-string' but ensure that the returned string
   1374 is loadable."
   1375   (let ((print-quoted t)
   1376         (print-length nil)
   1377         (print-level nil))
   1378     (prin1-to-string sexp)))
   1379 
   1380 (defun flycheck-string-to-number-safe (string)
   1381   "Safely convert STRING to a number.
   1382 
   1383 If STRING is of string type and a numeric string, convert STRING
   1384 to a number and return it.  Otherwise return nil."
   1385   (let ((number-re (rx string-start (one-or-more (any digit)) string-end)))
   1386     (when (and (stringp string) (string-match-p number-re string))
   1387       (string-to-number string))))
   1388 
   1389 (defun flycheck-string-or-nil-p (obj)
   1390   "Determine if OBJ is a string or nil."
   1391   (or (null obj) (stringp obj)))
   1392 
   1393 (defun flycheck-string-list-p (obj)
   1394   "Determine if OBJ is a list of strings."
   1395   (and (listp obj) (seq-every-p #'stringp obj)))
   1396 
   1397 (defun flycheck-string-or-string-list-p (obj)
   1398   "Determine if OBJ is a string or a list of strings."
   1399   (or (stringp obj) (flycheck-string-list-p obj)))
   1400 
   1401 (defun flycheck-symbol-list-p (obj)
   1402   "Determine if OBJ is a list of symbols."
   1403   (and (listp obj) (seq-every-p #'symbolp obj)))
   1404 
   1405 (defvar-local flycheck--file-truename-cache nil)
   1406 
   1407 (defun flycheck--file-truename (file)
   1408   "Memoize the result of `file-truename' on (directory-file-name FILE)."
   1409   ;; `file-truename' is slow, but alternatives are incomplete, so memoizing is
   1410   ;; our best bet.  See https://github.com/flycheck/flycheck/pull/1698.
   1411   (unless flycheck--file-truename-cache
   1412     (setq-local flycheck--file-truename-cache (make-hash-table :test 'equal)))
   1413   (or (gethash file flycheck--file-truename-cache)
   1414       (puthash file (file-truename (directory-file-name file))
   1415                flycheck--file-truename-cache)))
   1416 
   1417 (defun flycheck-same-files-p (file-a file-b)
   1418   "Determine whether FILE-A and FILE-B refer to the same file.
   1419 
   1420 Files are the same if (in the order checked) they are equal, or
   1421 if they resolve to the same canonical paths."
   1422   (or (string= file-a file-b)
   1423       (string= (flycheck--file-truename file-a)
   1424                (flycheck--file-truename file-b))))
   1425 
   1426 (defvar-local flycheck-temporaries nil
   1427   "Temporary files and directories created by Flycheck.")
   1428 
   1429 (defun flycheck-temp-dir-system ()
   1430   "Create a unique temporary directory.
   1431 
   1432 Use `flycheck-temp-prefix' as prefix, and add the directory to
   1433 `flycheck-temporaries'.
   1434 
   1435 Return the path of the directory"
   1436   (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory)))
   1437     (push tempdir flycheck-temporaries)
   1438     tempdir))
   1439 
   1440 (defun flycheck-temp-file-system (filename &optional suffix)
   1441   "Create a temporary file named after FILENAME.
   1442 
   1443 If FILENAME is non-nil, this function creates a temporary
   1444 directory with `flycheck-temp-dir-system', and creates a file
   1445 with the same name as FILENAME in this directory.
   1446 
   1447 Otherwise this function creates a temporary file starting with
   1448 `flycheck-temp-prefix'.  If present, SUFFIX is appended;
   1449 otherwise, a random suffix is used.  The path of the file is
   1450 added to `flycheck-temporaries'.
   1451 
   1452 Return the path of the file."
   1453   (let ((tempfile (convert-standard-filename
   1454                    (if filename
   1455                        (expand-file-name (file-name-nondirectory filename)
   1456                                          (flycheck-temp-dir-system))
   1457                      (make-temp-file flycheck-temp-prefix nil suffix)))))
   1458     (push tempfile flycheck-temporaries)
   1459     tempfile))
   1460 
   1461 (defun flycheck-temp-file-inplace (filename &optional suffix)
   1462   "Create an in-place copy of FILENAME.
   1463 
   1464 Prefix the file with `flycheck-temp-prefix' and add the path of
   1465 the file to `flycheck-temporaries'.
   1466 
   1467 If FILENAME is nil, fall back to `flycheck-temp-file-system' with
   1468 the specified SUFFIX.
   1469 
   1470 Return the path of the file."
   1471   (if filename
   1472       (let* ((tempname (format "%s_%s"
   1473                                flycheck-temp-prefix
   1474                                (file-name-nondirectory filename)))
   1475              (tempfile (convert-standard-filename
   1476                         (expand-file-name tempname
   1477                                           (file-name-directory filename)))))
   1478         (push tempfile flycheck-temporaries)
   1479         tempfile)
   1480     (flycheck-temp-file-system filename suffix)))
   1481 
   1482 (defun flycheck-temp-directory (checker)
   1483   "Return the directory where CHECKER writes temporary files.
   1484 
   1485 Return nil if the CHECKER does not write temporary files."
   1486   (let ((args (flycheck-checker-arguments checker)))
   1487     (cond
   1488      ((memq 'source args) temporary-file-directory)
   1489      ((memq 'source-inplace args)
   1490       (if buffer-file-name (file-name-directory buffer-file-name)
   1491         temporary-file-directory))
   1492      (t nil))))
   1493 
   1494 (defun flycheck-temp-files-writable-p (checker)
   1495   "Whether CHECKER can write temporary files.
   1496 
   1497 If CHECKER has `source' or `source-inplace' in its `:command',
   1498 return whether flycheck has the permissions to create the
   1499 respective temporary files.
   1500 
   1501 Return t if CHECKER does not use temporary files."
   1502   (let ((dir (flycheck-temp-directory checker)))
   1503     (or (not dir) (file-writable-p dir))))
   1504 
   1505 (defun flycheck-save-buffer-to-file (file-name)
   1506   "Save the contents of the current buffer to FILE-NAME."
   1507   (make-directory (file-name-directory file-name) t)
   1508   (let ((jka-compr-inhibit t))
   1509     (write-region nil nil file-name nil 0)))
   1510 
   1511 (defun flycheck-save-buffer-to-temp (temp-file-fn)
   1512   "Save buffer to temp file returned by TEMP-FILE-FN.
   1513 
   1514 Return the name of the temporary file."
   1515   (let ((filename (funcall temp-file-fn (buffer-file-name))))
   1516     ;; Do not flush short-lived temporary files onto disk
   1517     (let ((write-region-inhibit-fsync t))
   1518       (flycheck-save-buffer-to-file filename))
   1519     filename))
   1520 
   1521 (defun flycheck-prepend-with-option (option items &optional prepend-fn)
   1522   "Prepend OPTION to each item in ITEMS, using PREPEND-FN.
   1523 
   1524 Prepend OPTION to each item in ITEMS.
   1525 
   1526 ITEMS is a list of strings to pass to the syntax checker.  OPTION
   1527 is the option, as string.  PREPEND-FN is a function called to
   1528 prepend OPTION to each item in ITEMS.  It receives the option and
   1529 a single item from ITEMS as argument, and must return a string or
   1530 a list of strings with OPTION prepended to the item.  If
   1531 PREPEND-FN is nil or omitted, use `list'.
   1532 
   1533 Return a list of strings where OPTION is prepended to each item
   1534 in ITEMS using PREPEND-FN.  If PREPEND-FN returns a list, it is
   1535 spliced into the resulting list."
   1536   (unless (stringp option)
   1537     (error "Option %S is not a string" option))
   1538   (unless prepend-fn
   1539     (setq prepend-fn #'list))
   1540   (let ((prepend
   1541          (lambda (item)
   1542            (let ((result (funcall prepend-fn option item)))
   1543              (cond
   1544               ((and (listp result) (seq-every-p #'stringp result)) result)
   1545               ((stringp result) (list result))
   1546               (t (error "Invalid result type for option: %S" result)))))))
   1547     (apply #'append (seq-map prepend items))))
   1548 
   1549 (defun flycheck-find-in-buffer (pattern)
   1550   "Find PATTERN in the current buffer.
   1551 
   1552 Return the result of the first matching group of PATTERN, or nil,
   1553 if PATTERN did not match."
   1554   (save-excursion
   1555     (save-restriction
   1556       (widen)
   1557       (goto-char (point-min))
   1558       (when (re-search-forward pattern nil 'no-error)
   1559         (match-string-no-properties 1)))))
   1560 
   1561 (defun flycheck-buffer-empty-p (&optional buffer)
   1562   "Check whether a BUFFER is empty, defaulting to the current one."
   1563   (= (buffer-size buffer) 0))
   1564 
   1565 (defun flycheck-buffer-nonempty-p (&optional buffer)
   1566   "Check whether a BUFFER is nonempty, defaulting to the current one."
   1567   (> (buffer-size buffer) 0))
   1568 
   1569 (defun flycheck-ephemeral-buffer-p ()
   1570   "Determine whether the current buffer is an ephemeral buffer.
   1571 
   1572 See Info node `(elisp)Buffer Names' for information about
   1573 ephemeral buffers."
   1574   (string-prefix-p " " (buffer-name)))
   1575 
   1576 (defun flycheck-encrypted-buffer-p ()
   1577   "Determine whether the current buffer is an encrypted file.
   1578 
   1579 See Info node `(epa)Top' for Emacs' interface to encrypted
   1580 files."
   1581   ;; The EPA file handler sets this variable locally to remember the recipients
   1582   ;; of the encrypted file for re-encryption.  Hence, a local binding of this
   1583   ;; variable is a good indication that the buffer is encrypted.  I haven't
   1584   ;; found any better indicator anyway.
   1585   (local-variable-p 'epa-file-encrypt-to))
   1586 
   1587 (defun flycheck-autoloads-file-p ()
   1588   "Determine whether the current buffer is an autoloads file.
   1589 
   1590 Autoloads are generated by package.el during installation."
   1591   (string-suffix-p "-autoloads.el" (buffer-name)))
   1592 
   1593 (defun flycheck-in-user-emacs-directory-p (filename)
   1594   "Whether FILENAME is in `user-emacs-directory'."
   1595   (string-prefix-p (file-name-as-directory
   1596                     (flycheck--file-truename user-emacs-directory))
   1597                    (flycheck--file-truename filename)))
   1598 
   1599 (defun flycheck-safe-delete (file-or-dir)
   1600   "Safely delete FILE-OR-DIR."
   1601   (ignore-errors
   1602     (if (file-directory-p file-or-dir)
   1603         (delete-directory file-or-dir 'recursive)
   1604       (delete-file file-or-dir))))
   1605 
   1606 (defun flycheck-safe-delete-temporaries ()
   1607   "Safely delete all temp files and directories of Flycheck.
   1608 
   1609 Safely delete all files and directories listed in
   1610 `flycheck-temporaries' and set the variable's value to nil."
   1611   (seq-do #'flycheck-safe-delete flycheck-temporaries)
   1612   (setq flycheck-temporaries nil))
   1613 
   1614 (defun flycheck-rx-file-name (form)
   1615   "Translate the `(file-name)' FORM into a regular expression."
   1616   (let ((body (or (cdr form) '((minimal-match
   1617                                 (one-or-more not-newline))))))
   1618     (rx-to-string `(group-n 1 ,@body) t)))
   1619 
   1620 (defun flycheck-rx-message (form)
   1621   "Translate the `(message)' FORM into a regular expression."
   1622   (let ((body (or (cdr form) '((one-or-more not-newline)))))
   1623     (rx-to-string `(group-n 4 ,@body) t)))
   1624 
   1625 (defun flycheck-rx-id (form)
   1626   "Translate the `(id)' FORM into a regular expression."
   1627   (rx-to-string `(group-n 5 ,@(cdr form)) t))
   1628 
   1629 (defun flycheck-rx-to-string (form &optional no-group)
   1630   "Like `rx-to-string' for FORM, but with special keywords:
   1631 
   1632 `line'
   1633      matches the initial line number.
   1634 
   1635 `column'
   1636      matches the initial column number.
   1637 
   1638 `end-line'
   1639      matches the final line number.
   1640 
   1641 `end-column'
   1642      matches the final column number (exclusive).
   1643 
   1644 
   1645 `(file-name SEXP ...)'
   1646      matches the file name.  SEXP describes the file name.  If no
   1647      SEXP is given, use a default body of `(minimal-match
   1648      (one-or-more not-newline))'.
   1649 
   1650 `(message SEXP ...)'
   1651      matches the message.  SEXP constitutes the body of the
   1652      message.  If no SEXP is given, use a default body
   1653      of `(one-or-more not-newline)'.
   1654 
   1655 `(id SEXP ...)'
   1656      matches an error ID.  SEXP describes the ID.
   1657 
   1658 NO-GROUP is passed to `rx-to-string'.
   1659 
   1660 See `rx' for a complete list of all built-in `rx' forms."
   1661   (let ((rx-constituents
   1662          (append
   1663           `((file-name flycheck-rx-file-name 0 nil) ;; group 1
   1664             (line . ,(rx (group-n 2 (one-or-more digit))))
   1665             (column . ,(rx (group-n 3 (one-or-more digit))))
   1666             (message flycheck-rx-message 0 nil) ;; group 4
   1667             (id flycheck-rx-id 0 nil) ;; group 5
   1668             (end-line . ,(rx (group-n 6 (one-or-more digit))))
   1669             (end-column . ,(rx (group-n 7 (one-or-more digit)))))
   1670           rx-constituents nil)))
   1671     (rx-to-string form no-group)))
   1672 
   1673 (defun flycheck-current-load-file ()
   1674   "Get the source file currently being loaded.
   1675 
   1676 Always return the name of the corresponding source file, never
   1677 any byte-compiled file.
   1678 
   1679 Return nil, if the currently loaded file cannot be determined."
   1680   (when-let* ((this-file (cond
   1681                           (load-in-progress load-file-name)
   1682                           ((bound-and-true-p byte-compile-current-file))
   1683                           (t (buffer-file-name))))
   1684               ;; A best guess for the source file of a compiled library. Works
   1685               ;; well in most cases, and especially for ELPA packages
   1686               (source-file (concat (file-name-sans-extension this-file)
   1687                                    ".el")))
   1688     (when (file-exists-p source-file)
   1689       source-file)))
   1690 
   1691 (defun flycheck-module-root-directory (module &optional file-name)
   1692   "Get the root directory for a MODULE in FILE-NAME.
   1693 
   1694 MODULE is a qualified module name, either a string with
   1695 components separated by a dot, or as list of components.
   1696 FILE-NAME is the name of the file or directory containing the
   1697 module as string.  When nil or omitted, defaults to the return
   1698 value of function `buffer-file-name'.
   1699 
   1700 Return the root directory of the module, that is, the directory,
   1701 from which FILE-NAME can be reached by descending directories
   1702 along each part of MODULE.
   1703 
   1704 If the MODULE name does not match the directory hierarchy upwards
   1705 from FILE-NAME, return the directory containing FILE-NAME.  When
   1706 FILE-NAME is nil, return `default-directory'."
   1707   (let ((file-name (or file-name (buffer-file-name)))
   1708         (module-components (if (stringp module)
   1709                                (split-string module (rx "."))
   1710                              (copy-sequence module))))
   1711     (if (and module-components file-name)
   1712         (let ((parts (nreverse module-components))
   1713               (base-directory (directory-file-name
   1714                                (file-name-sans-extension file-name))))
   1715           (while (and parts
   1716                       (string= (file-name-nondirectory base-directory)
   1717                                (car parts)))
   1718             (pop parts)
   1719             (setq base-directory (directory-file-name
   1720                                   (file-name-directory base-directory))))
   1721           (file-name-as-directory base-directory))
   1722       (if file-name
   1723           (file-name-directory file-name)
   1724         (expand-file-name default-directory)))))
   1725 
   1726 (cl-defstruct (flycheck-line-cache
   1727                (:constructor flycheck-line-cache-new))
   1728   "Cache structure used to speed up `flycheck-goto-line'."
   1729   tick point line)
   1730 
   1731 (defvar-local flycheck--line-cache nil
   1732   "Cache used to speed ip `flycheck-goto-line'.")
   1733 
   1734 (defsubst flycheck--init-line-cache ()
   1735   "Initialize or reinitialize `flycheck--line-cache'."
   1736   (let ((tick (buffer-modified-tick)))
   1737     (if flycheck--line-cache
   1738         (unless (= (flycheck-line-cache-tick flycheck--line-cache) tick)
   1739           (setf (flycheck-line-cache-tick flycheck--line-cache) tick
   1740                 (flycheck-line-cache-point flycheck--line-cache) 1
   1741                 (flycheck-line-cache-line flycheck--line-cache) 1))
   1742       (setq-local flycheck--line-cache
   1743                   (flycheck-line-cache-new :tick tick :point 1 :line 1)))))
   1744 
   1745 (defun flycheck-goto-line (line)
   1746   "Move point to beginning of line number LINE.
   1747 
   1748 This function assumes that the current buffer is not narrowed."
   1749   (flycheck--init-line-cache)
   1750   (goto-char (flycheck-line-cache-point flycheck--line-cache))
   1751   (let ((delta (- line (flycheck-line-cache-line flycheck--line-cache))))
   1752     (when (= 0 (forward-line delta))
   1753       (setf (flycheck-line-cache-point flycheck--line-cache) (point))
   1754       (setf (flycheck-line-cache-line flycheck--line-cache) line))))
   1755 
   1756 (defun flycheck-line-column-to-position (line column)
   1757   "Return the point closest to LINE, COLUMN on line LINE.
   1758 
   1759 COLUMN is one-based."
   1760   (save-excursion
   1761     (flycheck-goto-line line)
   1762     (min (+ (point) (1- column)) (line-end-position))))
   1763 
   1764 (defun flycheck-line-column-at-point ()
   1765   "Return the line and column number at point."
   1766   (cons (line-number-at-pos) (1+ (- (point) (line-beginning-position)))))
   1767 
   1768 (defun flycheck-line-column-at-pos (pos)
   1769   "Return the line and column number at position POS.
   1770 
   1771 COLUMN is one-based."
   1772   (let ((inhibit-field-text-motion t))
   1773     (save-excursion
   1774       (goto-char pos)
   1775       (flycheck-line-column-at-point))))
   1776 
   1777 
   1778 ;;; Minibuffer tools
   1779 (defvar flycheck-read-checker-history nil
   1780   "`completing-read' history of `flycheck-read-checker'.")
   1781 
   1782 (defun flycheck-completing-read (prompt candidates default &optional history)
   1783   "Read a value from the minibuffer.
   1784 
   1785 Use `flycheck-completing-read-function' to read input from the
   1786 minibuffer with completion.
   1787 
   1788 Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT.
   1789 HISTORY is passed to `flycheck-completing-read-function'.
   1790 
   1791 Note that `flycheck-completing-read-function' may return an empty
   1792 string instead of nil, even when \"\" isn't among the candidates.
   1793 See `completing-read' for more details."
   1794   (funcall flycheck-completing-read-function
   1795            prompt candidates nil 'require-match nil history default))
   1796 
   1797 (defun flycheck-read-checker (prompt &optional default property candidates)
   1798   "Read a flycheck checker from minibuffer with PROMPT and DEFAULT.
   1799 
   1800 PROMPT is a string to show in the minibuffer as prompt.  It
   1801 should end with a single space.  DEFAULT is a symbol denoting the
   1802 default checker to use, if the user did not select any checker.
   1803 PROPERTY is a symbol denoting a syntax checker property.  If
   1804 non-nil, only complete syntax checkers which have a non-nil value
   1805 for PROPERTY.  CANDIDATES is an optional list of all syntax
   1806 checkers available for completion, defaulting to all defined
   1807 checkers.  If given, PROPERTY is ignored.
   1808 
   1809 Return the checker as symbol, or DEFAULT if no checker was
   1810 chosen.  If DEFAULT is nil and no checker was chosen, signal a
   1811 `user-error' if the underlying completion system does not provide
   1812 a default on its own."
   1813   (when (and default (not (flycheck-valid-checker-p default)))
   1814     (error "%S is no valid Flycheck checker" default))
   1815   (let* ((candidates (seq-map #'symbol-name
   1816                               (or candidates
   1817                                   (flycheck-defined-checkers property))))
   1818          (default (and default (symbol-name default)))
   1819          (input (flycheck-completing-read
   1820                  prompt candidates default
   1821                  'flycheck-read-checker-history)))
   1822     (when (string-empty-p input)
   1823       (unless default
   1824         (user-error "No syntax checker selected"))
   1825       (setq input default))
   1826     (let ((checker (intern input)))
   1827       (unless (flycheck-valid-checker-p checker)
   1828         (error "%S is not a valid Flycheck syntax checker" checker))
   1829       checker)))
   1830 
   1831 (defun flycheck-read-error-level (prompt)
   1832   "Read an error level from the user with PROMPT.
   1833 
   1834 Only offers level for which errors currently exist, in addition
   1835 to the default levels."
   1836   (let* ((levels (seq-map #'flycheck-error-level
   1837                           (flycheck-error-list-current-errors)))
   1838          (levels-with-defaults (append '(info warning error) levels))
   1839          (uniq-levels (seq-uniq levels-with-defaults))
   1840          (level (flycheck-completing-read prompt uniq-levels nil)))
   1841     (when (string-empty-p level) (setq level nil))
   1842     (and level (intern level))))
   1843 
   1844 
   1845 ;;; Checker API
   1846 (defun flycheck-defined-checkers (&optional property)
   1847   "Find all defined syntax checkers, optionally with PROPERTY.
   1848 
   1849 PROPERTY is a symbol.  If given, only return syntax checkers with
   1850 a non-nil value for PROPERTY.
   1851 
   1852 The returned list is sorted alphapetically by the symbol name of
   1853 the syntax checkers."
   1854   (let (defined-checkers)
   1855     (mapatoms (lambda (symbol)
   1856                 (when (and (flycheck-valid-checker-p symbol)
   1857                            (or (null property)
   1858                                (flycheck-checker-get symbol property)))
   1859                   (push symbol defined-checkers))))
   1860     (sort defined-checkers #'string<)))
   1861 
   1862 (defun flycheck-registered-checker-p (checker)
   1863   "Determine whether CHECKER is registered.
   1864 
   1865 A checker is registered if it is contained in
   1866 `flycheck-checkers'."
   1867   (and (flycheck-valid-checker-p checker)
   1868        (memq checker flycheck-checkers)))
   1869 
   1870 (defun flycheck-disabled-checker-p (checker)
   1871   "Determine whether CHECKER is disabled, manually or automatically."
   1872   (or (flycheck-manually-disabled-checker-p checker)
   1873       (flycheck-automatically-disabled-checker-p checker)))
   1874 
   1875 (defun flycheck-manually-disabled-checker-p (checker)
   1876   "Determine whether CHECKER has been manually disabled.
   1877 
   1878 A checker has been manually disabled if it is contained in
   1879 `flycheck-disabled-checkers'."
   1880   (memq checker flycheck-disabled-checkers))
   1881 
   1882 (defun flycheck-automatically-disabled-checker-p (checker)
   1883   "Determine whether CHECKER has been automatically disabled.
   1884 
   1885 A checker has been automatically disabled if it is contained in
   1886 `flycheck--automatically-disabled-checkers'."
   1887   (memq checker flycheck--automatically-disabled-checkers))
   1888 
   1889 
   1890 ;;; Generic syntax checkers
   1891 (defconst flycheck-generic-checker-version 2
   1892   "The internal version of generic syntax checker declarations.
   1893 
   1894 Flycheck will not use syntax checkers whose generic version is
   1895 less than this constant.")
   1896 
   1897 (defsubst flycheck--checker-property-name (property)
   1898   "Return the SYMBOL property for checker PROPERTY."
   1899   (intern (concat "flycheck-" (symbol-name property))))
   1900 
   1901 (defun flycheck-checker-get (checker property)
   1902   "Get the value of CHECKER's PROPERTY."
   1903   (get checker (flycheck--checker-property-name property)))
   1904 
   1905 (gv-define-setter flycheck-checker-get (value checker property)
   1906   `(setf (get ,checker (flycheck--checker-property-name ,property)) ,value))
   1907 
   1908 (defun flycheck-validate-next-checker (next &optional strict)
   1909   "Validate NEXT checker.
   1910 
   1911 With STRICT non-nil, also check whether the syntax checker and
   1912 the error level in NEXT are valid.  Otherwise just check whether
   1913 these are symbols.
   1914 
   1915 Signal an error if NEXT is not a valid entry for
   1916 `:next-checkers'."
   1917   (when (symbolp next)
   1918     (setq next (cons t next)))
   1919   (pcase next
   1920     (`(,level . ,checker)
   1921      (if strict
   1922          (progn
   1923            (unless (or (eq level t) (flycheck-error-level-p level))
   1924              (error "%S is not a valid Flycheck error level" level))
   1925            (unless (flycheck-valid-checker-p checker)
   1926              (error "%s is not a valid Flycheck syntax checker" checker)))
   1927        (unless (symbolp level)
   1928          (error "Error level %S must be a symbol" level))
   1929        (unless (symbolp checker)
   1930          (error "Checker %S must be a symbol" checker))))
   1931     (_ (error "%S must be a symbol or cons cell" next)))
   1932   t)
   1933 
   1934 (defun flycheck-define-generic-checker (symbol docstring &rest properties)
   1935   "Define SYMBOL as generic syntax checker.
   1936 
   1937 Any syntax checker defined with this macro is eligible for manual
   1938 syntax checker selection with `flycheck-select-checker'.  To make
   1939 the new syntax checker available for automatic selection, it must
   1940 be registered in `flycheck-checkers'.
   1941 
   1942 DOCSTRING is the documentation of the syntax checker, for
   1943 `flycheck-describe-checker'.  The following PROPERTIES constitute
   1944 a generic syntax checker.  Unless otherwise noted, all properties
   1945 are mandatory.
   1946 
   1947 `:start FUNCTION'
   1948      A function to start the syntax checker.
   1949 
   1950      FUNCTION shall take two arguments and return a context
   1951      object if the checker is started successfully.  Otherwise it
   1952      shall signal an error.
   1953 
   1954      The first argument is the syntax checker being started.  The
   1955      second is a callback function to report state changes to
   1956      Flycheck.  The callback takes two arguments STATUS DATA,
   1957      where STATUS is a symbol denoting the syntax checker status
   1958      and DATA an optional argument with additional data for the
   1959      status report.  See `flycheck-report-buffer-checker-status'
   1960      for more information about STATUS and DATA.
   1961 
   1962      FUNCTION may be synchronous or asynchronous, i.e. it may
   1963      call the given callback either immediately, or at some later
   1964      point (e.g. from a process sentinel).
   1965 
   1966      A syntax checker _must_ call CALLBACK at least once with a
   1967      STATUS that finishes the current syntax checker.  Otherwise
   1968      Flycheck gets stuck at the current syntax check with this
   1969      syntax checker.
   1970 
   1971      The context object returned by FUNCTION is passed to
   1972      `:interrupt'.
   1973 
   1974 `:interrupt FUNCTION'
   1975      A function to interrupt the syntax check.
   1976 
   1977      FUNCTION is called with the syntax checker and the context
   1978      object returned by the `:start' function and shall try to
   1979      interrupt the syntax check.  The context may be nil, if the
   1980      syntax check is interrupted before actually started.
   1981      FUNCTION should handle this situation.
   1982 
   1983      If it cannot interrupt the syntax check, it may either
   1984      signal an error or silently ignore the attempt to interrupt
   1985      the syntax checker, depending on the severity of the
   1986      situation.
   1987 
   1988      If interrupting the syntax check failed, Flycheck will let
   1989      the syntax check continue, but ignore any status reports.
   1990      Notably, it won't highlight any errors reported by the
   1991      syntax check in the buffer.
   1992 
   1993      This property is optional.  If omitted, Flycheck won't
   1994      attempt to interrupt syntax checks with this syntax checker,
   1995      and simply ignore their results.
   1996 
   1997 `:print-doc FUNCTION'
   1998      A function to print additional documentation into the Help
   1999      buffer of this checker.
   2000 
   2001      FUNCTION is called when creating the Help buffer for the
   2002      syntax checker, with the syntax checker as single argument,
   2003      after printing the name of the syntax checker and its modes
   2004      and predicate, but before printing DOCSTRING.  It may insert
   2005      additional documentation into the current buffer.
   2006 
   2007      The call occurs within `with-help-window'.  Hence
   2008      `standard-output' points to the current buffer, so you may
   2009      use `princ' and friends to add content.  Also, the current
   2010      buffer is put into Help mode afterwards, which automatically
   2011      turns symbols into references, if possible.
   2012 
   2013      This property is optional.  If omitted, no additional
   2014      documentation is printed for this syntax checker.
   2015 
   2016 :verify FUNCTION
   2017      A function to verify the checker for the current buffer.
   2018 
   2019      FUNCTION is called with the syntax checker as single
   2020      argument, and shall return a list of
   2021      `flycheck-verification-result' objects indicating whether
   2022      the syntax checker could be used in the current buffer, and
   2023      highlighting potential setup problems.
   2024 
   2025      This property is optional.  If omitted, no additional
   2026      verification occurs for this syntax checker.  It is however
   2027      absolutely recommended that you add a `:verify' function to
   2028      your syntax checker, because it will help users to spot
   2029      potential setup problems.
   2030 
   2031 `:modes MODES'
   2032      A major mode symbol or a list thereof, denoting major modes
   2033      to use this syntax checker in.
   2034 
   2035      This syntax checker will only be used in buffers whose
   2036      `major-mode' is contained in MODES.
   2037 
   2038      If `:predicate' is also given the syntax checker will only
   2039      be used in buffers for which the `:predicate' returns
   2040      non-nil.
   2041 
   2042 `:predicate FUNCTION'
   2043      A function to determine whether to use the syntax checker in
   2044      the current buffer.
   2045 
   2046      FUNCTION is called without arguments and shall return
   2047      non-nil if this syntax checker shall be used to check the
   2048      current buffer.  Otherwise it shall return nil.
   2049 
   2050      If this checker has a `:working-directory' FUNCTION is
   2051      called with `default-directory' bound to the checker's
   2052      working directory.
   2053 
   2054      FUNCTION is only called in matching major modes.
   2055 
   2056      This property is optional.
   2057 
   2058 `:enabled FUNCTION'
   2059      A function to determine whether to use the syntax checker in
   2060      the current buffer.
   2061 
   2062      This property behaves as `:predicate', except that it's only
   2063      called the first time a syntax checker is to be used in a buffer.
   2064 
   2065      FUNCTION is called without arguments and shall return
   2066      non-nil if this syntax checker shall be used to check the
   2067      current buffer.  Otherwise it shall return nil.
   2068 
   2069      If FUNCTION returns a non-nil value the checker is put in a
   2070      whitelist in `flycheck--automatically-enabled-checkers' to
   2071      prevent further invocations of `:enabled'.  Otherwise it is
   2072      disabled via `flycheck--automatically-disabled-checkers' to
   2073      prevent any further use of it.
   2074 
   2075      If this checker has a `:working-directory' FUNCTION is
   2076      called with `default-directory' bound to the checker's
   2077      working directory.
   2078 
   2079      FUNCTION is only called in matching major modes.
   2080 
   2081      This property is optional.
   2082 
   2083 `:error-filter FUNCTION'
   2084      A function to filter the errors returned by this checker.
   2085 
   2086      FUNCTION is called with the list of `flycheck-error' objects
   2087      returned by the syntax checker and shall return another list
   2088      of `flycheck-error' objects, which is considered the final
   2089      result of this syntax checker.
   2090 
   2091      FUNCTION is free to add, remove or modify errors, whether in
   2092      place or by copying.
   2093 
   2094      This property is optional.  The default filter is
   2095      `identity'.
   2096 
   2097 `:error-explainer FUNCTION'
   2098      A function to return an explanation text for errors
   2099      generated by this checker.
   2100 
   2101      FUNCTION is called with a `flycheck-error' object, in the
   2102      buffer of that error.  It shall return an explanation
   2103      message for the error.
   2104 
   2105      The message can take any of the following forms:
   2106      - A string, which will be displayed to the user
   2107      - A function (likely a closure), which will be called with
   2108        `standard-output' set to a `flycheck-explain-error-mode'
   2109        buffer, and should write to it.
   2110      - A cons `(url . ,URL), indicating that the explanation can
   2111        be found online at URL.
   2112      - nil if there is no explanation for this error.
   2113 
   2114      If URL is provided by the checker, and cannot be composed
   2115      from other elements in the `flycheck-error' object, consider
   2116      passing the URL via text properties:
   2117 
   2118        ;; During the error object creation
   2119        (put-text-property 0 1 \\='explainer-url .url .check_id)
   2120 
   2121        ;; In the error-explainer FUNCTION
   2122        (let ((id (flycheck-error-id err)))
   2123          (and id `(url . ,(get-text-property 0 \\='explainer-url id))))
   2124 
   2125      This property is optional.
   2126 
   2127 `:next-checkers NEXT-CHECKERS'
   2128      A list denoting syntax checkers to apply after this syntax
   2129      checker, in what we call \"chaining\" of syntax checkers.
   2130 
   2131      Each ITEM is a cons cell `(LEVEL . CHECKER)'.  CHECKER is a
   2132      syntax checker to run after this syntax checker.  LEVEL is
   2133      an error level.  CHECKER will only be used if there are no
   2134      current errors of at least LEVEL.  LEVEL may also be t, in
   2135      which case CHECKER is used regardless of the current errors.
   2136 
   2137      ITEM may also be a syntax checker symbol, which is
   2138      equivalent to `(t . ITEM)'.
   2139 
   2140      Flycheck tries all items in order of declaration, and uses
   2141      the first whose LEVEL matches and whose CHECKER is
   2142      registered and can be used for the current buffer.
   2143 
   2144      This feature is typically used to apply more than one syntax
   2145      checker to a buffer.  For instance, you might first use a
   2146      compiler to check a buffer for syntax and type errors, and
   2147      then run a linting tool that checks for insecure code, or
   2148      questionable style.
   2149 
   2150      This property is optional.  If omitted, it defaults to the
   2151      nil, i.e. no other syntax checkers are applied after this
   2152      syntax checker.
   2153 
   2154 `:working-directory FUNCTION'
   2155      The value of `default-directory' when invoking `:start'.
   2156 
   2157      FUNCTION is a function taking the syntax checker as sole
   2158      argument.  It shall return the absolute path to an existing
   2159      directory to use as `default-directory' for `:start' or
   2160      nil to fall back to the `default-directory' of the current
   2161      buffer.
   2162 
   2163      This property is optional.  If omitted, invoke `:start'
   2164      from the `default-directory' of the buffer being checked.
   2165 
   2166 Signal an error, if any property has an invalid value."
   2167   (declare (indent 1)
   2168            (doc-string 2))
   2169   (let ((start (plist-get properties :start))
   2170         (interrupt (plist-get properties :interrupt))
   2171         (print-doc (plist-get properties :print-doc))
   2172         (modes (plist-get properties :modes))
   2173         (predicate (plist-get properties :predicate))
   2174         (verify (plist-get properties :verify))
   2175         (enabled (plist-get properties :enabled))
   2176         (filter (or (plist-get properties :error-filter) #'identity))
   2177         (explainer (plist-get properties :error-explainer))
   2178         (next-checkers (plist-get properties :next-checkers))
   2179         (file (flycheck-current-load-file))
   2180         (working-directory (plist-get properties :working-directory)))
   2181 
   2182     (unless (listp modes)
   2183       (setq modes (list modes)))
   2184 
   2185     (unless (functionp start)
   2186       (error ":start %S of syntax checker %s is not a function" start symbol))
   2187     (unless (or (null interrupt) (functionp interrupt))
   2188       (error ":interrupt %S of syntax checker %s is not a function"
   2189              interrupt symbol))
   2190     (unless (or (null print-doc) (functionp print-doc))
   2191       (error ":print-doc %S of syntax checker %s is not a function"
   2192              print-doc symbol))
   2193     (unless (or (null verify) (functionp verify))
   2194       (error ":verify %S of syntax checker %S is not a function"
   2195              verify symbol))
   2196     (unless (or (null enabled) (functionp enabled))
   2197       (error ":enabled %S of syntax checker %S is not a function"
   2198              enabled symbol))
   2199     (unless modes
   2200       (error "Missing :modes in syntax checker %s" symbol))
   2201     (dolist (mode modes)
   2202       (unless (symbolp mode)
   2203         (error "Invalid :modes %s in syntax checker %s, %s must be a symbol"
   2204                modes symbol mode)))
   2205     (unless (or (null predicate) (functionp predicate))
   2206       (error ":predicate %S of syntax checker %s  is not a function"
   2207              predicate symbol))
   2208     (unless (functionp filter)
   2209       (error ":error-filter %S of syntax checker %s is not a function"
   2210              filter symbol))
   2211     (unless (or (null explainer) (functionp explainer))
   2212       (error ":error-explainer %S of syntax checker %S is not a function"
   2213              explainer symbol))
   2214     (dolist (checker next-checkers)
   2215       (flycheck-validate-next-checker checker))
   2216 
   2217     (let ((real-predicate
   2218            (and predicate
   2219                 (lambda ()
   2220                   ;; Run predicate in the checker's default directory
   2221                   (let ((default-directory
   2222                           (flycheck-compute-working-directory symbol)))
   2223                     (funcall predicate)))))
   2224           (real-enabled
   2225            (lambda ()
   2226              (if (flycheck-valid-checker-p symbol)
   2227                  (or (null enabled)
   2228                      ;; Run enabled in the checker's default directory
   2229                      (let ((default-directory
   2230                              (flycheck-compute-working-directory symbol)))
   2231                        (funcall enabled)))
   2232                (lwarn 'flycheck
   2233                       :warning "%S is no valid Flycheck syntax checker.
   2234 Try to reinstall the package defining this syntax checker." symbol)
   2235                nil))))
   2236       (pcase-dolist (`(,prop . ,value)
   2237                      `((start             . ,start)
   2238                        (interrupt         . ,interrupt)
   2239                        (print-doc         . ,print-doc)
   2240                        (modes             . ,modes)
   2241                        (predicate         . ,real-predicate)
   2242                        (verify            . ,verify)
   2243                        (enabled           . ,real-enabled)
   2244                        (error-filter      . ,filter)
   2245                        (error-explainer   . ,explainer)
   2246                        (next-checkers     . ,next-checkers)
   2247                        (documentation     . ,docstring)
   2248                        (file              . ,file)
   2249                        (working-directory . ,working-directory)))
   2250         (setf (flycheck-checker-get symbol prop) value)))
   2251 
   2252     ;; Track the version, to avoid breakage if the internal format changes
   2253     (setf (flycheck-checker-get symbol 'generic-checker-version)
   2254           flycheck-generic-checker-version)))
   2255 
   2256 (defun flycheck-valid-checker-p (checker)
   2257   "Check whether a CHECKER is valid.
   2258 
   2259 A valid checker is a symbol defined as syntax checker with
   2260 `flycheck-define-checker'."
   2261   (and (symbolp checker)
   2262        (= (or (get checker 'flycheck-generic-checker-version) 0)
   2263           flycheck-generic-checker-version)))
   2264 
   2265 (defun flycheck-checker-supports-major-mode-p (checker &optional mode)
   2266   "Whether CHECKER supports the given major MODE.
   2267 
   2268 CHECKER is a syntax checker symbol and MODE a major mode symbol.
   2269 Look at the `modes' property of CHECKER to determine whether
   2270 CHECKER supports buffers in the given major MODE.
   2271 
   2272 MODE defaults to the value of `major-mode' if omitted or nil.
   2273 
   2274 Return non-nil if CHECKER supports MODE and nil otherwise."
   2275   (let ((mode (or mode major-mode)))
   2276     (memq mode (flycheck-checker-get checker 'modes))))
   2277 
   2278 (define-obsolete-variable-alias 'flycheck-enabled-checkers
   2279   'flycheck--automatically-enabled-checkers "32")
   2280 
   2281 (defvar flycheck--automatically-enabled-checkers nil
   2282   "Syntax checkers included in automatic selection.
   2283 
   2284 A list of Flycheck syntax checkers included in automatic
   2285 selection for the current buffer.")
   2286 (make-variable-buffer-local 'flycheck--automatically-enabled-checkers)
   2287 
   2288 (defun flycheck-may-enable-checker (checker)
   2289   "Whether a generic CHECKER may be enabled for current buffer.
   2290 
   2291 Return non-nil if CHECKER may be used for the current buffer, and
   2292 nil otherwise.  The result of the `:enabled' check, if any, is
   2293 cached."
   2294   (and
   2295    ;; May only enable valid checkers
   2296    (flycheck-valid-checker-p checker)
   2297    ;; Don't run the :enabled check if the checker is already disabled…
   2298    (not (flycheck-disabled-checker-p checker))
   2299    (or
   2300     ;; …or if we've already cached the result
   2301     (memq checker flycheck--automatically-enabled-checkers)
   2302     (let* ((enabled (flycheck-checker-get checker 'enabled))
   2303            (may-enable (or (null enabled) (funcall enabled))))
   2304       ;; Cache the result
   2305       (if may-enable
   2306           (cl-pushnew checker flycheck--automatically-enabled-checkers)
   2307         (cl-pushnew checker flycheck--automatically-disabled-checkers))
   2308       may-enable))))
   2309 
   2310 (defun flycheck-reset-enabled-checker (checker)
   2311   "Reset the `:enabled' test of CHECKER.
   2312 
   2313 Forget that CHECKER has been enabled or automatically disabled
   2314 from a previous `:enabled' test.  The result of the `:enabled'
   2315 test is cached in `flycheck-may-enable-checker': if you wish to
   2316 test the `:enabled' predicate again, you must first reset its
   2317 state using this function."
   2318   (when (memq checker flycheck--automatically-disabled-checkers)
   2319     (setq flycheck--automatically-disabled-checkers
   2320           (remq checker flycheck--automatically-disabled-checkers)))
   2321   (when (memq checker flycheck--automatically-enabled-checkers)
   2322     (setq flycheck--automatically-enabled-checkers
   2323           (remq checker flycheck--automatically-enabled-checkers)))
   2324   (flycheck-buffer))
   2325 
   2326 (defun flycheck-may-use-checker (checker)
   2327   "Whether a generic CHECKER may be used.
   2328 
   2329 Return non-nil if CHECKER may be used for the current buffer, and
   2330 nil otherwise."
   2331   (let ((predicate (flycheck-checker-get checker 'predicate)))
   2332     (and (flycheck-valid-checker-p checker)
   2333          (flycheck-checker-supports-major-mode-p checker)
   2334          (flycheck-may-enable-checker checker)
   2335          (or (null predicate) (funcall predicate)))))
   2336 
   2337 (defun flycheck-may-use-next-checker (next-checker)
   2338   "Determine whether NEXT-CHECKER may be used."
   2339   (when (symbolp next-checker)
   2340     (push t next-checker))
   2341   (let ((level (car next-checker))
   2342         (next-checker (cdr next-checker)))
   2343     (and (or (eq level t)
   2344              (flycheck-has-max-current-errors-p level))
   2345          (flycheck-registered-checker-p next-checker)
   2346          (flycheck-may-use-checker next-checker))))
   2347 
   2348 
   2349 ;;; Help for generic syntax checkers
   2350 (define-button-type 'help-flycheck-checker-def
   2351   :supertype 'help-xref
   2352   'help-function #'flycheck-goto-checker-definition
   2353   'help-echo "mouse-1, RET: find Flycheck checker definition")
   2354 
   2355 (defconst flycheck-find-checker-regexp
   2356   (rx line-start (zero-or-more (syntax whitespace))
   2357       "(" symbol-start
   2358       (or "flycheck-define-checker" "flycheck-define-command-checker")
   2359       symbol-end
   2360       (eval (list 'regexp find-function-space-re))
   2361       (? "'")
   2362       symbol-start "%s" symbol-end
   2363       (or (syntax whitespace) line-end))
   2364   "Regular expression to find a checker definition.")
   2365 
   2366 (add-to-list 'find-function-regexp-alist
   2367              '(flycheck-checker . flycheck-find-checker-regexp))
   2368 
   2369 (defun flycheck-goto-checker-definition (checker file)
   2370   "Go to to the definition of CHECKER in FILE."
   2371   (let ((location (find-function-search-for-symbol
   2372                    checker 'flycheck-checker file)))
   2373     (pop-to-buffer (car location))
   2374     (if (cdr location)
   2375         (goto-char (cdr location))
   2376       (message "Unable to find checker location in file"))))
   2377 
   2378 (defun flycheck-checker-at-point ()
   2379   "Return the Flycheck checker found at or before point.
   2380 
   2381 Return nil if there is no checker."
   2382   (let ((symbol (variable-at-point 'any-symbol)))
   2383     (when (flycheck-valid-checker-p symbol)
   2384       symbol)))
   2385 
   2386 (defun flycheck-describe-checker (checker)
   2387   "Display the documentation of CHECKER.
   2388 
   2389 CHECKER is a checker symbol.
   2390 
   2391 Pop up a help buffer with the documentation of CHECKER."
   2392   (interactive
   2393    (let* ((enable-recursive-minibuffers t)
   2394           (default (or (flycheck-checker-at-point)
   2395                        (ignore-errors (flycheck-get-checker-for-buffer))))
   2396           (prompt (if default
   2397                       (format "Describe syntax checker (default %s): " default)
   2398                     "Describe syntax checker: ")))
   2399      (list (flycheck-read-checker prompt default))))
   2400   (unless (flycheck-valid-checker-p checker)
   2401     (user-error "You didn't specify a Flycheck syntax checker"))
   2402   (let ((filename (flycheck-checker-get checker 'file))
   2403         (modes (flycheck-checker-get checker 'modes))
   2404         (predicate (flycheck-checker-get checker 'predicate))
   2405         (print-doc (flycheck-checker-get checker 'print-doc))
   2406         (next-checkers (flycheck-checker-get checker 'next-checkers))
   2407         (help-xref-following
   2408          ;; Ensure that we don't reuse buffers like `flycheck-verify-checker',
   2409          ;; and that we don't error out if a `help-flycheck-checker-doc' button
   2410          ;; is added outside of a documentation window.
   2411          (and help-xref-following (eq major-mode 'help-mode))))
   2412     (help-setup-xref (list #'flycheck-describe-checker checker)
   2413                      (called-interactively-p 'interactive))
   2414     (save-excursion
   2415       (with-help-window (help-buffer)
   2416         (princ (format "%s is a Flycheck syntax checker" checker))
   2417         (when filename
   2418           (princ (format " in `%s'" (file-name-nondirectory filename)))
   2419           (with-current-buffer standard-output
   2420             (save-excursion
   2421               (re-search-backward "`\\([^`']+\\)'" nil t)
   2422               (help-xref-button 1 'help-flycheck-checker-def
   2423                                 checker filename))))
   2424         (princ ".\n\n")
   2425 
   2426         (let ((modes-start (with-current-buffer standard-output (point-max))))
   2427           ;; Track the start of the modes documentation, to properly re-fill
   2428           ;; it later
   2429           (princ "  This syntax checker checks syntax in the major mode(s) ")
   2430           (princ (string-join
   2431                   (seq-map (apply-partially #'format "`%s'") modes)
   2432                   ", "))
   2433           (when predicate
   2434             (princ ", and uses a custom predicate"))
   2435           (princ ".")
   2436           (when next-checkers
   2437             (princ "  It runs the following checkers afterwards:"))
   2438           (with-current-buffer standard-output
   2439             (save-excursion
   2440               (fill-region-as-paragraph modes-start (point-max))))
   2441           (princ "\n")
   2442 
   2443           ;; Print the list of next checkers
   2444           (when next-checkers
   2445             (princ "\n")
   2446             (let ((beg-checker-list (with-current-buffer standard-output
   2447                                       (point))))
   2448               (dolist (next-checker next-checkers)
   2449                 (if (symbolp next-checker)
   2450                     (princ (format "     * `%s'\n" next-checker))
   2451                   (princ (format "     * `%s' (maximum level `%s')\n"
   2452                                  (cdr next-checker) (car next-checker)))))
   2453               ;;
   2454               (with-current-buffer standard-output
   2455                 (save-excursion
   2456                   (while (re-search-backward "`\\([^`']+\\)'"
   2457                                              beg-checker-list t)
   2458                     (let ((checker (intern-soft (match-string 1))))
   2459                       (when (flycheck-valid-checker-p checker)
   2460                         (help-xref-button 1 'help-flycheck-checker-doc
   2461                                           checker)))))))))
   2462         ;; Call the custom print-doc function of the checker, if present
   2463         (when print-doc
   2464           (funcall print-doc checker))
   2465         ;; Ultimately, print the docstring
   2466         (princ "\nDocumentation:\n")
   2467         (princ (flycheck-checker-get checker 'documentation))))))
   2468 
   2469 
   2470 ;;; Syntax checker verification
   2471 (cl-defstruct (flycheck-verification-result
   2472                (:constructor flycheck-verification-result-new))
   2473   "Structure for storing a single verification result.
   2474 
   2475 Slots:
   2476 
   2477 `label'
   2478      A label for this result, as string
   2479 
   2480 `message'
   2481      A message for this result, as string
   2482 
   2483 `face'
   2484      The face to use for the `message'.
   2485 
   2486      You can either use a face symbol, or a list of face symbols."
   2487   label message face)
   2488 
   2489 (defun flycheck-verify-generic-checker (checker)
   2490   "Verify a generic CHECKER in the current buffer.
   2491 
   2492 Return a list of `flycheck-verification-result' objects."
   2493   (let (results
   2494         (predicate (flycheck-checker-get checker 'predicate))
   2495         (enabled (flycheck-checker-get checker 'enabled))
   2496         (verify (flycheck-checker-get checker 'verify)))
   2497     (when enabled
   2498       (let ((result (funcall enabled)))
   2499         (push (flycheck-verification-result-new
   2500                :label (propertize "may enable" 'help-echo ":enable")
   2501                :message (if result "yes" "no")
   2502                :face (if result 'success '(bold warning)))
   2503               results)))
   2504     (when predicate
   2505       (let ((result (funcall predicate)))
   2506         (push (flycheck-verification-result-new
   2507                :label (propertize "may run" 'help-echo ":predicate")
   2508                :message (prin1-to-string (not (null result)))
   2509                :face (if result 'success '(bold warning)))
   2510               results)))
   2511     (append (nreverse results)
   2512             (and verify (funcall verify checker)))))
   2513 
   2514 (define-button-type 'help-flycheck-checker-doc
   2515   :supertype 'help-xref
   2516   'help-function #'flycheck-describe-checker
   2517   'help-echo "mouse-1, RET: describe Flycheck checker")
   2518 
   2519 (define-button-type 'flycheck-button
   2520   'follow-link t
   2521   'action (lambda (pos)
   2522             (apply (get-text-property pos 'flycheck-action)
   2523                    (get-text-property pos 'flycheck-data))
   2524             ;; Revert the verify-setup buffer since it is now stale
   2525             (revert-buffer))
   2526   'face 'flycheck-verify-select-checker)
   2527 
   2528 (define-button-type 'flycheck-checker-select
   2529   :supertype 'flycheck-button
   2530   'flycheck-action (lambda (buffer checker)
   2531                      (with-current-buffer buffer
   2532                        (flycheck-select-checker checker)))
   2533   'help-echo "mouse-1, RET: select this checker")
   2534 
   2535 (define-button-type 'flycheck-checker-enable
   2536   :supertype 'flycheck-button
   2537   'flycheck-action (lambda (buffer checker)
   2538                      (interactive)
   2539                      (with-current-buffer buffer
   2540                        (flycheck--toggle-checker checker t)
   2541                        (flycheck-buffer)))
   2542   'help-echo "mouse-1, RET: re-enable this checker in this buffer")
   2543 
   2544 (define-button-type 'flycheck-checker-reset-enabled
   2545   :supertype 'flycheck-button
   2546   'flycheck-action (lambda (buffer checker)
   2547                      (with-current-buffer buffer
   2548                        (flycheck-reset-enabled-checker checker)))
   2549   'help-echo "mouse-1, RET: try to re-enable this checker")
   2550 
   2551 (defun flycheck--verify-princ-checker (checker buffer
   2552                                                &optional with-mm with-select)
   2553   "Print verification result of CHECKER for BUFFER.
   2554 
   2555 When WITH-MM is given and non-nil, also include the major mode
   2556 into the verification results.
   2557 
   2558 When WITH-SELECT is non-nil, add a button to select this checker."
   2559   (princ "  ")
   2560   (insert-button (symbol-name checker)
   2561                  'type 'help-flycheck-checker-doc
   2562                  'help-args (list checker))
   2563   (cond
   2564    ((with-current-buffer buffer
   2565       (flycheck-manually-disabled-checker-p checker))
   2566     (insert (propertize " (manually disabled) " 'face '(bold error)))
   2567     (insert-text-button "enable"
   2568                         'type 'flycheck-checker-enable
   2569                         'flycheck-data (list buffer checker)))
   2570    ((with-current-buffer buffer
   2571       (flycheck-automatically-disabled-checker-p checker))
   2572     (insert (propertize " (automatically disabled) " 'face '(bold error)))
   2573     (insert-text-button "reset"
   2574                         'type 'flycheck-checker-reset-enabled
   2575                         'flycheck-data (list buffer checker))))
   2576   (when (eq checker (buffer-local-value 'flycheck-checker buffer))
   2577     (insert (propertize " (explicitly selected)" 'face 'bold)))
   2578   (when with-select
   2579     (princ "  ")
   2580     (insert-text-button "select"
   2581                         'type 'flycheck-checker-select
   2582                         'flycheck-data (list buffer checker)))
   2583   (princ "\n")
   2584   (let ((results (with-current-buffer buffer
   2585                    (append (flycheck-verify-generic-checker checker)
   2586                            (flycheck--verify-next-checkers checker)))))
   2587     (when with-mm
   2588       (with-current-buffer buffer
   2589         (let ((message-and-face
   2590                (if (flycheck-checker-supports-major-mode-p checker)
   2591                    (cons (format "`%s' supported" major-mode) 'success)
   2592                  (cons (format "`%s' not supported" major-mode) 'error))))
   2593           (push (flycheck-verification-result-new
   2594                  :label "major mode"
   2595                  :message (car message-and-face)
   2596                  :face (cdr message-and-face))
   2597                 results))))
   2598     (let* ((label-length
   2599             (seq-max (mapcar
   2600                       (lambda (res)
   2601                         (length (flycheck-verification-result-label res)))
   2602                       results)))
   2603            (message-column (+ 8 label-length)))
   2604       (dolist (result results)
   2605         (princ "    - ")
   2606         (princ (flycheck-verification-result-label result))
   2607         (princ ": ")
   2608         (princ (make-string (- message-column (current-column)) ?\ ))
   2609         (let ((message (flycheck-verification-result-message result))
   2610               (face (flycheck-verification-result-face result)))
   2611           ;; If face is nil, using propertize erases the face already contained
   2612           ;; by the message.  We don't want that, since this would remove the
   2613           ;; button face from the checker chain result.
   2614           (insert (if face (propertize message 'face face) message)))
   2615         (princ "\n"))))
   2616   (princ "\n"))
   2617 
   2618 (defun flycheck--get-next-checker-symbol (next)
   2619   "Get the checker symmbol of NEXT checker.
   2620 
   2621 NEXT should be either a cons (NEXT-CHECKER . LEVEL) or a
   2622 symbol."
   2623   (if (consp next) (cdr next) next))
   2624 
   2625 (defun flycheck-get-next-checkers (checker)
   2626   "Return the immediate next checkers of CHECKER.
   2627 
   2628 This is a list of checker symbols.  The error levels of the
   2629 `:next-checker' property are ignored."
   2630   (mapcar #'flycheck--get-next-checker-symbol
   2631           (flycheck-checker-get checker 'next-checkers)))
   2632 
   2633 (defun flycheck-all-next-checkers (checker)
   2634   "Return all checkers that may follow CHECKER.
   2635 
   2636 Return the transitive closure of the next-checker relation.  The
   2637 return value is a list of checkers, not including CHECKER."
   2638   (let ((next-checkers)
   2639         (visited)
   2640         (queue (list checker)))
   2641     (while queue
   2642       (let ((c (pop queue)))
   2643         (push c visited)
   2644         (dolist (n (flycheck-get-next-checkers c))
   2645           (push n next-checkers)
   2646           (unless (memq n visited)
   2647             (cl-pushnew n queue)))))
   2648     (seq-uniq next-checkers)))
   2649 
   2650 (defun flycheck--verify-next-checkers (checker)
   2651   "Return a verification result for the next checkers of CHECKER."
   2652   (when-let (next (flycheck-get-next-checkers checker))
   2653     (list
   2654      (flycheck-verification-result-new
   2655       :label "next checkers"
   2656       ;; We use `make-text-button' to preserve the button properties in the
   2657       ;; string
   2658       :message (mapconcat
   2659                 (lambda (checker)
   2660                   (make-text-button (symbol-name checker) nil
   2661                                     'type 'help-flycheck-checker-doc
   2662                                     'help-args (list checker)))
   2663                 next
   2664                 ", ")))))
   2665 
   2666 (defun flycheck--verify-print-header (desc buffer)
   2667   "Print a title with DESC for BUFFER in the current buffer.
   2668 
   2669 DESC is an arbitrary string containing a description, and BUFFER
   2670 is the buffer being verified.  The name and the major mode mode
   2671 of BUFFER are printed.
   2672 
   2673 DESC and information about BUFFER are printed in the current
   2674 buffer."
   2675   (princ desc)
   2676   (insert (propertize (buffer-name buffer) 'face 'bold))
   2677   (princ " in ")
   2678   (let ((mode (buffer-local-value 'major-mode buffer)))
   2679     (insert-button (symbol-name mode)
   2680                    'type 'help-function
   2681                    'help-args (list mode)))
   2682   (princ ":\n\n"))
   2683 
   2684 (defun flycheck--verify-print-footer (buffer)
   2685   "Print a footer for BUFFER in the current buffer.
   2686 
   2687 BUFFER is the buffer being verified."
   2688   (princ "Flycheck Mode is ")
   2689   (let ((enabled (buffer-local-value 'flycheck-mode buffer)))
   2690     (insert (propertize (if enabled "enabled" "disabled")
   2691                         'face (if enabled 'success '(warning bold)))))
   2692   (princ
   2693    (with-current-buffer buffer
   2694      ;; Use key binding state in the verified buffer to print the help.
   2695      (substitute-command-keys
   2696       ".  Use \\[universal-argument] \\[flycheck-disable-checker] \
   2697 to enable disabled checkers.")))
   2698   (save-excursion
   2699     (let ((end (point)))
   2700       (backward-paragraph)
   2701       (fill-region-as-paragraph (point) end)))
   2702 
   2703   (princ "\n\n--------------------\n\n")
   2704   (princ (format "Flycheck version: %s\n" (flycheck--pkg-version)))
   2705   (princ (format "Emacs version:    %s\n" emacs-version))
   2706   (princ (format "System:           %s\n" system-configuration))
   2707   (princ (format "Window system:    %S\n" window-system)))
   2708 
   2709 (define-derived-mode flycheck-verify-mode help-mode
   2710   "Flycheck verification"
   2711   "Major mode to display Flycheck verification results."
   2712   ;; `help-mode-finish' will restore `buffer-read-only'
   2713   (setq buffer-read-only nil))
   2714 
   2715 (defun flycheck-verify-checker (checker)
   2716   "Check whether a CHECKER can be used in this buffer.
   2717 
   2718 Show a buffer listing possible problems that prevent CHECKER from
   2719 being used for the current buffer.
   2720 
   2721 Note: Do not use this function to check whether a syntax checker
   2722 is applicable from Emacs Lisp code.  Use
   2723 `flycheck-may-use-checker' instead."
   2724   (interactive (list (flycheck-read-checker "Checker to verify: ")))
   2725   (unless (flycheck-valid-checker-p checker)
   2726     (user-error "%s is not a syntax checker" checker))
   2727 
   2728   ;; Save the buffer to make sure that all predicates are good
   2729   ;; FIXME: this may be surprising to users, with unintended side-effects.
   2730   (when (and (buffer-file-name) (buffer-modified-p))
   2731     (save-buffer))
   2732 
   2733   (let ((buffer (current-buffer)))
   2734     (with-help-window "*Flycheck checker*"
   2735       (with-current-buffer standard-output
   2736         (flycheck-verify-mode)
   2737         (flycheck--verify-print-header "Syntax checker in buffer " buffer)
   2738         (flycheck--verify-princ-checker checker buffer 'with-mm)
   2739         (if (with-current-buffer buffer (flycheck-may-use-checker checker))
   2740             (insert (propertize
   2741                      "Flycheck can use this syntax checker for this buffer.\n"
   2742                      'face 'success))
   2743           (insert (propertize
   2744                    "Flycheck cannot use this syntax checker for this buffer.\n"
   2745                    'face 'error)))
   2746         (insert "\n")
   2747         (flycheck--verify-print-footer buffer)))))
   2748 
   2749 (defun flycheck-verify-setup ()
   2750   "Check whether Flycheck can be used in this buffer.
   2751 
   2752 Display a new buffer listing all syntax checkers that could be
   2753 applicable in the current buffer.  For each syntax checkers,
   2754 possible problems are shown."
   2755   (interactive)
   2756   ;; Save to make sure checkers that only work on saved buffers will pass the
   2757   ;; verification
   2758   (when (and (buffer-file-name) (buffer-modified-p))
   2759     (save-buffer))
   2760 
   2761   (let* ((buffer (current-buffer))
   2762          (first-checker (flycheck-get-checker-for-buffer))
   2763          (valid-checkers
   2764           (remq first-checker
   2765                 (seq-filter #'flycheck-may-use-checker flycheck-checkers)))
   2766          (valid-next-checkers
   2767           (when first-checker
   2768             (seq-intersection valid-checkers
   2769                               (flycheck-all-next-checkers first-checker))))
   2770          (valid-remaining (seq-difference valid-checkers valid-next-checkers))
   2771          (other-checkers
   2772           (seq-difference (seq-filter #'flycheck-checker-supports-major-mode-p
   2773                                       flycheck-checkers)
   2774                           (cons first-checker valid-checkers))))
   2775 
   2776     ;; Print all applicable checkers for this buffer
   2777     (with-help-window "*Flycheck checkers*"
   2778       (with-current-buffer standard-output
   2779         (flycheck-verify-mode)
   2780 
   2781         (flycheck--verify-print-header "Syntax checkers for buffer " buffer)
   2782 
   2783         (if first-checker
   2784             (progn
   2785               (princ "First checker to run:\n\n")
   2786               (flycheck--verify-princ-checker first-checker buffer))
   2787           (insert (propertize
   2788                    "No checker to run in this buffer.\n\n"
   2789                    'face '(bold error))))
   2790 
   2791         (when valid-next-checkers
   2792           (princ
   2793            "Checkers that may run as part of the first checker's chain:\n\n")
   2794           (dolist (checker valid-next-checkers)
   2795             (flycheck--verify-princ-checker checker buffer)))
   2796 
   2797         (when valid-remaining
   2798           (princ "Checkers that could run if selected:\n\n")
   2799           (dolist (checker valid-remaining)
   2800             (flycheck--verify-princ-checker checker buffer nil 'with-select)))
   2801 
   2802         (when other-checkers
   2803           (princ
   2804            "Checkers that are compatible with this mode, \
   2805 but will not run until properly configured:\n\n")
   2806           (dolist (checker other-checkers)
   2807             (flycheck--verify-princ-checker checker buffer)))
   2808 
   2809         ;; If we have no checkers at all, that's worth mentioning
   2810         (unless (or first-checker valid-checkers other-checkers)
   2811           (insert (propertize
   2812                    "No checkers are available for this buffer.\n\n"
   2813                    'face '(bold error))))
   2814 
   2815         (let ((unregistered-checkers
   2816                (seq-difference (flycheck-defined-checkers) flycheck-checkers)))
   2817           (when unregistered-checkers
   2818             (insert (propertize
   2819                      "The following syntax checkers are not registered:\n"
   2820                      'face '(bold warning)))
   2821             (dolist (checker unregistered-checkers)
   2822               (princ "  - ")
   2823               (princ checker)
   2824               (princ "\n"))
   2825             (princ
   2826              "Try adding these syntax checkers to `flycheck-checkers'.\n\n")))
   2827 
   2828         (flycheck--verify-print-footer buffer)
   2829 
   2830         (setq-local revert-buffer-function
   2831                     (lambda (_ignore-auto _noconfirm)
   2832                       (with-current-buffer buffer (flycheck-verify-setup))))))))
   2833 
   2834 
   2835 ;;; Predicates for generic syntax checkers
   2836 (defun flycheck-buffer-saved-p (&optional buffer)
   2837   "Determine whether BUFFER is saved to a file.
   2838 
   2839 BUFFER is the buffer to check.  If omitted or nil, use the
   2840 current buffer as BUFFER.
   2841 
   2842 Return non-nil if the BUFFER is backed by a file, and not
   2843 modified, or nil otherwise."
   2844   (let ((file-name (buffer-file-name buffer)))
   2845     (and file-name (file-exists-p file-name) (not (buffer-modified-p buffer)))))
   2846 
   2847 
   2848 ;;; Extending generic checkers
   2849 (defun flycheck-remove-next-checker (checker next)
   2850   "After CHECKER remove a NEXT checker.
   2851 
   2852 CHECKER is a syntax checker symbol, from which to remove NEXT
   2853 checker.
   2854 
   2855 NEXT is a cons or a symbol, as documented in
   2856 `flycheck-add-next-checker'."
   2857   (unless (flycheck-valid-checker-p checker)
   2858     (error "%s is not a valid syntax checker" checker))
   2859   (let* ((next-symbol (flycheck--get-next-checker-symbol next)))
   2860     (setf
   2861      (flycheck-checker-get checker 'next-checkers)
   2862      (seq-remove
   2863       (lambda (next) (eq (flycheck--get-next-checker-symbol next) next-symbol))
   2864       (flycheck-checker-get checker 'next-checkers)))))
   2865 
   2866 (defun flycheck-add-next-checker (checker next &optional append)
   2867   "After CHECKER add a NEXT checker.
   2868 
   2869 CHECKER is a syntax checker symbol, to which to add NEXT checker.
   2870 
   2871 NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'.  NEXT-CHECKER is a
   2872 symbol denoting the syntax checker to run after CHECKER.  LEVEL
   2873 is an error level.  NEXT-CHECKER will only be used if there is no
   2874 current error whose level is more severe than LEVEL.  LEVEL may
   2875 also be t, in which case NEXT-CHECKER is used regardless of the
   2876 current errors.
   2877 
   2878 NEXT can also be a syntax checker symbol only, which is
   2879 equivalent to `(t . NEXT)'.
   2880 
   2881 NEXT-CHECKER is prepended before other next checkers, unless
   2882 APPEND is non-nil."
   2883   (unless (flycheck-valid-checker-p checker)
   2884     (error "%s is not a valid syntax checker" checker))
   2885   (flycheck-validate-next-checker next 'strict)
   2886   (flycheck-remove-next-checker checker next)
   2887   (let ((next-checkers (flycheck-checker-get checker 'next-checkers)))
   2888     (setf (flycheck-checker-get checker 'next-checkers)
   2889           (if append (append next-checkers (list next))
   2890             (cons next next-checkers)))))
   2891 
   2892 (defun flycheck-add-mode (checker mode)
   2893   "To CHECKER add a new major MODE.
   2894 
   2895 CHECKER and MODE are symbols denoting a syntax checker and a
   2896 major mode respectively.
   2897 
   2898 Add MODE to the `:modes' property of CHECKER, so that CHECKER
   2899 will be used in buffers with MODE."
   2900   (unless (flycheck-valid-checker-p checker)
   2901     (error "%s is not a valid syntax checker" checker))
   2902   (unless (symbolp mode)
   2903     (error "%s is not a symbol" mode))
   2904   (push mode (flycheck-checker-get checker 'modes)))
   2905 
   2906 
   2907 ;;; Generic syntax checks
   2908 (cl-defstruct (flycheck-syntax-check
   2909                (:constructor flycheck-syntax-check-new))
   2910   "Structure for storing syntax check state.
   2911 
   2912 Slots:
   2913 
   2914 `buffer'
   2915      The buffer being checked.
   2916 
   2917 `checker'
   2918      The syntax checker being used.
   2919 
   2920 `context'
   2921      The context object.
   2922 
   2923 `working-directory'
   2924      Working directory for the syntax checker. Serve as a value for
   2925      `default-directory' for a checker."
   2926   buffer checker context working-directory)
   2927 
   2928 (defun flycheck-syntax-check-start (syntax-check callback)
   2929   "Start a SYNTAX-CHECK with CALLBACK."
   2930   (let ((checker (flycheck-syntax-check-checker syntax-check))
   2931         (default-directory
   2932           (flycheck-syntax-check-working-directory syntax-check)))
   2933     (setf (flycheck-syntax-check-context syntax-check)
   2934           (funcall (flycheck-checker-get checker 'start) checker callback))))
   2935 
   2936 (defun flycheck-syntax-check-interrupt (syntax-check)
   2937   "Interrupt a SYNTAX-CHECK."
   2938   (let* ((checker (flycheck-syntax-check-checker syntax-check))
   2939          (interrupt-fn (flycheck-checker-get checker 'interrupt))
   2940          (context (flycheck-syntax-check-context syntax-check)))
   2941     (when interrupt-fn
   2942       (funcall interrupt-fn checker context))))
   2943 
   2944 
   2945 ;;; Syntax checking mode
   2946 
   2947 (defvar flycheck-mode-map
   2948   (let ((map (make-sparse-keymap)))
   2949     (define-key map flycheck-keymap-prefix flycheck-command-map)
   2950     ;; We place the menu under a custom menu key.  Since this menu key is not
   2951     ;; present in the menu of the global map, no top-level menu entry is added
   2952     ;; to the global menu bar.  However, it still appears on the mode line
   2953     ;; lighter.
   2954     (define-key map [menu-bar flycheck] flycheck-mode-menu-map)
   2955     map)
   2956   "Keymap of command `flycheck-mode'.")
   2957 
   2958 (defvar-local flycheck-old-next-error-function nil
   2959   "Remember the old `next-error-function'.")
   2960 
   2961 (defconst flycheck-hooks-alist
   2962   '(
   2963     ;; Handle events that may start automatic syntax checks
   2964     (after-save-hook        . flycheck-handle-save)
   2965     (after-change-functions . flycheck-handle-change)
   2966     ;; Handle events that may triggered pending deferred checks
   2967     (window-configuration-change-hook . flycheck-perform-deferred-syntax-check)
   2968     (post-command-hook                . flycheck-perform-deferred-syntax-check)
   2969     ;; Teardown Flycheck whenever the buffer state is about to get lost, to
   2970     ;; clean up temporary files and directories.
   2971     (kill-buffer-hook       . flycheck-teardown)
   2972     (change-major-mode-hook . flycheck-teardown)
   2973     (before-revert-hook     . flycheck-teardown)
   2974     ;; Update the error list if necessary
   2975     (post-command-hook . flycheck-error-list-update-source)
   2976     (post-command-hook . flycheck-error-list-highlight-errors)
   2977     ;; Display errors.  Show errors at point after commands (like movements) and
   2978     ;; when Emacs gets focus.  Cancel the display timer when Emacs looses focus
   2979     ;; (as there's no need to display errors if the user can't see them), and
   2980     ;; hide the error buffer (for large error messages) if necessary.  Note that
   2981     ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined
   2982     ;; hooks are perfectly ok we don't need a version guard here.  They'll just
   2983     ;; not work silently.
   2984     (post-command-hook . flycheck-display-error-at-point-soon)
   2985     (focus-in-hook     . flycheck-display-error-at-point-soon)
   2986     (focus-out-hook    . flycheck-cancel-error-display-error-at-point-timer)
   2987     (post-command-hook . flycheck-hide-error-buffer)
   2988     ;; Immediately show error popups when navigating to an error
   2989     (next-error-hook . flycheck-display-error-at-point))
   2990   "Hooks which Flycheck needs to hook in.
   2991 
   2992 The `car' of each pair is a hook variable, the `cdr' a function
   2993 to be added or removed from the hook variable if Flycheck mode is
   2994 enabled and disabled respectively.")
   2995 
   2996 ;;;###autoload
   2997 (define-minor-mode flycheck-mode
   2998   "Flycheck is a minor mode for on-the-fly syntax checking.
   2999 
   3000 In `flycheck-mode' the buffer is automatically syntax-checked
   3001 using the first suitable syntax checker from `flycheck-checkers'.
   3002 Use `flycheck-select-checker' to select a checker for the current
   3003 buffer manually.
   3004 
   3005 If you run into issues, use `\\[flycheck-verify-setup]' to get help.
   3006 
   3007 Flycheck supports many languages out of the box, and many
   3008 additional ones are available on MELPA.  Adding new ones is very
   3009 easy.  Complete documentation is available online at URL
   3010 `https://www.flycheck.org/en/latest/'.  Please report issues and
   3011 request features at URL `https://github.com/flycheck/flycheck'.
   3012 
   3013 Flycheck displays its status in the mode line.  In the default
   3014 configuration, it looks like this:
   3015 
   3016 `FlyC'     This buffer has not been checked yet.
   3017 `FlyC*'    Flycheck is running.  Expect results soon!
   3018 `FlyC:0'   Last check resulted in no errors and no warnings.
   3019 `FlyC:3|5' This buffer contains three errors and five warnings.
   3020            Use `\\[flycheck-list-errors]' to see the list.
   3021 `FlyC-'    Flycheck doesn't have a checker for this buffer.
   3022 
   3023 You may also see the following icons:
   3024 `FlyC!'    The checker crashed.
   3025 `FlyC.'    The last syntax check was manually interrupted.
   3026 `FlyC?'    The checker did something unexpected, like exiting with 1
   3027            but returning no errors.
   3028 
   3029 The following keybindings are available in `flycheck-mode':
   3030 
   3031 \\{flycheck-mode-map}
   3032 \(you can change the prefix by customizing
   3033 `flycheck-keymap-prefix')
   3034 
   3035 If called interactively, enable Flycheck mode if ARG is positive,
   3036 and disable it if ARG is zero or negative.  If called from Lisp,
   3037 also enable the mode if ARG is omitted or nil, and toggle it if
   3038 ARG is ‘toggle’; disable the mode otherwise."
   3039   :init-value nil
   3040   :keymap flycheck-mode-map
   3041   :lighter flycheck-mode-line
   3042   :after-hook (flycheck-buffer-automatically 'mode-enabled 'force-deferred)
   3043   (cond
   3044    (flycheck-mode
   3045     (flycheck-clear)
   3046 
   3047     (pcase-dolist (`(,hook . ,fn) (reverse flycheck-hooks-alist))
   3048       (add-hook hook fn nil 'local))
   3049 
   3050     (setq flycheck-old-next-error-function
   3051           (if flycheck-standard-error-navigation
   3052               next-error-function
   3053             :unset))
   3054     (when flycheck-standard-error-navigation
   3055       (setq next-error-function #'flycheck-next-error-function))
   3056 
   3057     ;; This hook must be added globally since otherwise we cannot
   3058     ;; detect a change from a buffer where Flycheck is enabled to a
   3059     ;; buffer where Flycheck is not enabled, and therefore cannot
   3060     ;; notice that there has been any change when the user switches
   3061     ;; back to the buffer where Flycheck is enabled.
   3062     (add-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
   3063    (t
   3064     (unless (eq flycheck-old-next-error-function :unset)
   3065       (setq next-error-function flycheck-old-next-error-function))
   3066 
   3067     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
   3068       (remove-hook hook fn 'local))
   3069 
   3070     (flycheck-teardown))))
   3071 
   3072 
   3073 ;;; Syntax checker selection for the current buffer
   3074 (defun flycheck-get-checker-for-buffer ()
   3075   "Find the checker for the current buffer.
   3076 
   3077 Use the selected checker for the current buffer, if any,
   3078 otherwise search for the best checker from `flycheck-checkers'.
   3079 
   3080 Return checker if there is a checker for the current buffer, or
   3081 nil otherwise."
   3082   (if flycheck-checker
   3083       (when (flycheck-may-use-checker flycheck-checker)
   3084         flycheck-checker)
   3085     (seq-find #'flycheck-may-use-checker flycheck-checkers)))
   3086 
   3087 (defun flycheck-get-next-checker-for-buffer (checker)
   3088   "Get the checker to run after CHECKER for the current buffer."
   3089   (let ((next (seq-find #'flycheck-may-use-next-checker
   3090                         (flycheck-checker-get checker 'next-checkers))))
   3091     (when next
   3092       (if (symbolp next) next (cdr next)))))
   3093 
   3094 (defun flycheck-select-checker (checker)
   3095   "Select CHECKER for the current buffer.
   3096 
   3097 CHECKER is a syntax checker symbol (see `flycheck-checkers') or
   3098 nil.  In the former case, use CHECKER for the current buffer,
   3099 otherwise deselect the current syntax checker (if any) and use
   3100 automatic checker selection via `flycheck-checkers'.
   3101 
   3102 If called interactively prompt for CHECKER.  With prefix arg
   3103 deselect the current syntax checker and enable automatic
   3104 selection again.
   3105 
   3106 Set `flycheck-checker' to CHECKER and automatically start a new
   3107 syntax check if the syntax checker changed.
   3108 
   3109 CHECKER will be used, even if it is not contained in
   3110 `flycheck-checkers', or if it is disabled via
   3111 `flycheck-disabled-checkers'."
   3112   (interactive
   3113    (if current-prefix-arg
   3114        (list nil)
   3115      (list (flycheck-read-checker "Select checker: "
   3116                                   (flycheck-get-checker-for-buffer)))))
   3117   (when (not (eq checker flycheck-checker))
   3118     (unless (or (not checker) (flycheck-may-use-checker checker))
   3119       (flycheck-verify-checker checker)
   3120       (user-error "Can't use syntax checker %S in this buffer" checker))
   3121     (setq flycheck-checker checker)
   3122     (when flycheck-mode
   3123       (flycheck-buffer))))
   3124 
   3125 (defun flycheck--toggle-checker (checker enable)
   3126   "Enable or disable CHECKER for the current buffer.
   3127 
   3128 If ENABLE, re-enable CHECKER by removing it from the buffer-local
   3129 value of `flycheck-disabled-checkers'.  Otherwise, add the syntax
   3130 checker to the buffer-local value of `flycheck-disabled-checkers'."
   3131   (cond
   3132    (enable
   3133     ;; We must use `remq' instead of `delq', because we must _not_ modify the
   3134     ;; list.  Otherwise we could potentially modify the global default value,
   3135     ;; in case the list is the global default.
   3136     (when (memq checker flycheck-disabled-checkers)
   3137       (setq flycheck-disabled-checkers
   3138             (remq checker flycheck-disabled-checkers)))
   3139     (when (memq checker flycheck--automatically-disabled-checkers)
   3140       (setq flycheck--automatically-disabled-checkers
   3141             (remq checker flycheck--automatically-disabled-checkers))))
   3142    (t (unless (memq checker flycheck-disabled-checkers)
   3143         (push checker flycheck-disabled-checkers)))))
   3144 
   3145 (defun flycheck-disable-checker (checker &optional enable)
   3146   "Interactively disable CHECKER for the current buffer.
   3147 
   3148 Prompt for a syntax checker to disable, and add the syntax
   3149 checker to the buffer-local value of
   3150 `flycheck-disabled-checkers'.
   3151 
   3152 With non-nil ENABLE or with prefix arg, prompt for a disabled
   3153 syntax checker and re-enable it by removing it from the
   3154 buffer-local value of `flycheck-disabled-checkers'."
   3155   (declare
   3156    (interactive-only "Directly set `flycheck-disabled-checkers' instead"))
   3157   (interactive
   3158    (let* ((enable current-prefix-arg)
   3159           (candidates (if enable
   3160                           (append flycheck-disabled-checkers
   3161                                   flycheck--automatically-disabled-checkers)
   3162                         flycheck-checkers))
   3163           (prompt (if enable "Enable syntax checker: "
   3164                     "Disable syntax checker: ")))
   3165      (when (and enable (not candidates))
   3166        (user-error "No syntax checkers disabled in this buffer"))
   3167      (list (flycheck-read-checker prompt nil nil candidates) enable)))
   3168   (unless checker
   3169     (user-error "No syntax checker given"))
   3170   (flycheck--toggle-checker checker enable)
   3171   (flycheck-buffer))
   3172 
   3173 
   3174 ;;; Syntax checks for the current buffer
   3175 (defvar-local flycheck-current-syntax-check nil
   3176   "The current syntax check in the this buffer.")
   3177 (put 'flycheck-current-syntax-check 'permanent-local t)
   3178 
   3179 (defun flycheck-start-current-syntax-check (checker)
   3180   "Start a syntax check in the current buffer with CHECKER.
   3181 
   3182 Set `flycheck-current-syntax-check' accordingly."
   3183   ;; Allocate the current syntax check *before* starting it.  This allows for
   3184   ;; synchronous checks, which call the status callback immediately in their
   3185   ;; start function.
   3186   (let* ((check
   3187           (flycheck-syntax-check-new
   3188            :buffer (current-buffer)
   3189            :checker checker
   3190            :context nil
   3191            :working-directory (flycheck-compute-working-directory checker)))
   3192          (callback (flycheck-buffer-status-callback check)))
   3193     (setq flycheck-current-syntax-check check)
   3194     (flycheck-report-status 'running)
   3195     (flycheck-syntax-check-start check callback)))
   3196 
   3197 (defun flycheck-running-p ()
   3198   "Determine whether a syntax check is running in the current buffer."
   3199   (not (null flycheck-current-syntax-check)))
   3200 
   3201 (defun flycheck-stop ()
   3202   "Stop any ongoing syntax check in the current buffer."
   3203   (when (flycheck-running-p)
   3204     (flycheck-syntax-check-interrupt flycheck-current-syntax-check)
   3205     ;; Remove the current syntax check, to reset Flycheck into a non-running
   3206     ;; state, and to make `flycheck-report-buffer-checker-status' ignore any
   3207     ;; status reports from the current syntax check.
   3208     (setq flycheck-current-syntax-check nil)
   3209     (flycheck-report-status 'interrupted)))
   3210 
   3211 (defun flycheck-buffer-status-callback (syntax-check)
   3212   "Create a status callback for SYNTAX-CHECK in the current buffer."
   3213   (lambda (&rest args)
   3214     (apply #'flycheck-report-buffer-checker-status
   3215            syntax-check args)))
   3216 
   3217 (defun flycheck-buffer ()
   3218   "Start checking syntax in the current buffer.
   3219 
   3220 Get a syntax checker for the current buffer with
   3221 `flycheck-get-checker-for-buffer', and start it."
   3222   (interactive)
   3223   (flycheck-clean-deferred-check)
   3224   (if flycheck-mode
   3225       (unless (flycheck-running-p)
   3226         ;; Clear error list and mark all overlays for deletion.  We do not
   3227         ;; delete all overlays immediately to avoid excessive re-displays and
   3228         ;; flickering, if the same errors gets highlighted again after the check
   3229         ;; completed.
   3230         (run-hooks 'flycheck-before-syntax-check-hook)
   3231         (flycheck-clear-errors)
   3232         (flycheck-mark-all-overlays-for-deletion)
   3233         (condition-case err
   3234             (let* ((checker (flycheck-get-checker-for-buffer)))
   3235               (if checker
   3236                   (flycheck-start-current-syntax-check checker)
   3237                 (flycheck-clear)
   3238                 (flycheck-report-status 'no-checker)))
   3239           (error
   3240            (flycheck-report-failed-syntax-check)
   3241            (signal (car err) (cdr err)))))
   3242     (user-error "Flycheck mode disabled")))
   3243 
   3244 (defun flycheck-report-buffer-checker-status
   3245     (syntax-check status &optional data)
   3246   "In BUFFER, report a SYNTAX-CHECK STATUS with DATA.
   3247 
   3248 SYNTAX-CHECK is the `flycheck-syntax-check' which reported
   3249 STATUS.  STATUS denotes the status of CHECKER, with an optional
   3250 DATA.  STATUS may be one of the following symbols:
   3251 
   3252 `errored'
   3253      The syntax checker has errored.  DATA is an optional error
   3254      message.
   3255 
   3256      This report finishes the current syntax check.
   3257 
   3258 `interrupted'
   3259      The syntax checker was interrupted.  DATA is ignored.
   3260 
   3261      This report finishes the current syntax check.
   3262 
   3263 `finished'
   3264      The syntax checker has finished with a proper error report
   3265      for the current buffer.  DATA is the (potentially empty)
   3266      list of `flycheck-error' objects reported by the syntax
   3267      check.
   3268 
   3269      This report finishes the current syntax check.
   3270 
   3271 `suspicious'
   3272      The syntax checker encountered a suspicious state, which the
   3273      user needs to be informed about.  DATA is an optional
   3274      message.
   3275 
   3276 A syntax checker _must_ report a status at least once with any
   3277 symbol that finishes the current syntax checker.  Otherwise
   3278 Flycheck gets stuck with the current syntax check.
   3279 
   3280 If CHECKER is not the currently used syntax checker in
   3281 `flycheck-current-syntax-check', the status report is largely
   3282 ignored.  Notably, any errors reported by the checker are
   3283 discarded."
   3284   (let ((buffer (flycheck-syntax-check-buffer syntax-check)))
   3285     ;; Ignore the status report if the buffer is gone, or if this syntax check
   3286     ;; isn't the current one in buffer (which can happen if this is an old
   3287     ;; report of an interrupted syntax check, and a new syntax check was started
   3288     ;; since this check was interrupted)
   3289     (when (and (buffer-live-p buffer)
   3290                (eq syntax-check
   3291                    (buffer-local-value 'flycheck-current-syntax-check buffer)))
   3292       (with-current-buffer buffer
   3293         (let ((checker (flycheck-syntax-check-checker syntax-check)))
   3294           (pcase status
   3295             ((or `errored `interrupted)
   3296              (flycheck-report-failed-syntax-check status)
   3297              (when (eq status 'errored)
   3298                ;; In case of error, show the error message
   3299                (message "Error from syntax checker %s: %s"
   3300                         checker (or data "UNKNOWN!"))))
   3301             (`suspicious
   3302              (when flycheck-mode
   3303                (message "Suspicious state from syntax checker %s: %s"
   3304                         checker (or data "UNKNOWN!")))
   3305              (flycheck-report-status 'suspicious))
   3306             (`finished
   3307              (when flycheck-mode
   3308                ;; Only report errors from the checker if Flycheck Mode is
   3309                ;; still enabled.
   3310                (flycheck-finish-current-syntax-check
   3311                 data
   3312                 (flycheck-syntax-check-working-directory syntax-check))))
   3313             (_
   3314              (error "Unknown status %s from syntax checker %s"
   3315                     status checker))))))))
   3316 
   3317 (defun flycheck-finish-current-syntax-check (errors working-dir)
   3318   "Finish the current syntax-check in the current buffer with ERRORS.
   3319 
   3320 ERRORS is a list of `flycheck-error' objects reported by the
   3321 current syntax check in `flycheck-current-syntax-check'.
   3322 
   3323 Report all ERRORS and potentially start any next syntax checkers.
   3324 
   3325 If the current syntax checker reported excessive errors, it is
   3326 disabled via `flycheck-disable-excessive-checker' for subsequent
   3327 syntax checks.
   3328 
   3329 Relative file names in ERRORS will be expanded relative to
   3330 WORKING-DIR."
   3331   (let* ((syntax-check flycheck-current-syntax-check)
   3332          (checker (flycheck-syntax-check-checker syntax-check))
   3333          (errors (flycheck-relevant-errors
   3334                   (flycheck-fill-and-expand-error-file-names
   3335                    (flycheck-filter-errors
   3336                     (flycheck-assert-error-list-p errors) checker)
   3337                    working-dir))))
   3338     (unless (flycheck-disable-excessive-checker checker errors)
   3339       (flycheck-report-current-errors errors))
   3340     (let ((next-checker (flycheck-get-next-checker-for-buffer checker)))
   3341       (if next-checker
   3342           (flycheck-start-current-syntax-check next-checker)
   3343         (setq flycheck-current-syntax-check nil)
   3344         (flycheck-report-status 'finished)
   3345         ;; Delete overlays only after the very last checker has run, to avoid
   3346         ;; flickering on intermediate re-displays
   3347         (flycheck-delete-marked-overlays)
   3348         (flycheck-error-list-refresh)
   3349         (run-hooks 'flycheck-after-syntax-check-hook)
   3350         (when (and flycheck-auto-display-errors-after-checking
   3351                    (eq (current-buffer) (window-buffer)))
   3352           (flycheck-display-error-at-point))
   3353         ;; Immediately try to run any pending deferred syntax check, which
   3354         ;; were triggered by intermediate automatic check event, to make sure
   3355         ;; that we quickly refine outdated error information
   3356         (flycheck-perform-deferred-syntax-check)))))
   3357 
   3358 (defun flycheck-disable-excessive-checker (checker errors)
   3359   "Disable CHECKER if it reported excessive ERRORS.
   3360 
   3361 If ERRORS has more items than `flycheck-checker-error-threshold',
   3362 add CHECKER to `flycheck--automatically-disabled-checkers', and
   3363 show a warning.
   3364 
   3365 Return t when CHECKER was disabled, or nil otherwise."
   3366   (when (and flycheck-checker-error-threshold
   3367              (> (length errors) flycheck-checker-error-threshold))
   3368     ;; Disable CHECKER for this buffer
   3369     ;; (`flycheck--automatically-disabled-checkers' is a local variable).
   3370     (lwarn '(flycheck syntax-checker) :warning
   3371            (substitute-command-keys
   3372             "Syntax checker %s reported too many errors (%s) and is disabled.
   3373 Use `\\[customize-variable] RET flycheck-checker-error-threshold' to
   3374 change the threshold or `\\[universal-argument] \
   3375 \\[flycheck-disable-checker]' to re-enable the checker.")
   3376            checker (length errors))
   3377     (push checker flycheck--automatically-disabled-checkers)
   3378     t))
   3379 
   3380 (defun flycheck-clear (&optional shall-interrupt)
   3381   "Clear all errors in the current buffer.
   3382 
   3383 With prefix arg or SHALL-INTERRUPT non-nil, also interrupt the
   3384 current syntax check."
   3385   (interactive "P")
   3386   (when shall-interrupt
   3387     (flycheck-stop))
   3388   (flycheck-delete-all-overlays)
   3389   (flycheck-clear-errors)
   3390   (flycheck-clear-displayed-error-messages)
   3391   (flycheck-error-list-refresh)
   3392   (flycheck-hide-error-buffer))
   3393 
   3394 (defun flycheck--empty-variables ()
   3395   "Empty variables used by Flycheck."
   3396   (kill-local-variable 'flycheck--file-truename-cache)
   3397   (kill-local-variable 'flycheck--idle-trigger-timer)
   3398   (kill-local-variable 'flycheck--idle-trigger-conditions)
   3399   (kill-local-variable 'flycheck--last-error-display-tick))
   3400 
   3401 (defun flycheck-teardown (&optional ignore-global)
   3402   "Teardown Flycheck in the current buffer.
   3403 
   3404 Completely clear the whole Flycheck state.  Remove overlays, kill
   3405 running checks, and empty all variables used by Flycheck.
   3406 
   3407 Unless optional argument IGNORE-GLOBAL is non-nil, check to see
   3408 if no more Flycheck buffers remain (aside from the current
   3409 buffer), and if so then clean up global hooks."
   3410   (flycheck-safe-delete-temporaries)
   3411   (flycheck-stop)
   3412   (flycheck-clean-deferred-check)
   3413   (flycheck-clear)
   3414   (flycheck-cancel-error-display-error-at-point-timer)
   3415   (flycheck--clear-idle-trigger-timer)
   3416   (flycheck--empty-variables)
   3417   (unless (or ignore-global
   3418               (seq-some (lambda (buf)
   3419                           (and (not (equal buf (current-buffer)))
   3420                                (buffer-local-value 'flycheck-mode buf)))
   3421                         (buffer-list)))
   3422     (flycheck-global-teardown 'ignore-local)))
   3423 
   3424 
   3425 ;;; Automatic syntax checking in a buffer
   3426 (defun flycheck-may-check-automatically (&rest conditions)
   3427   "Determine whether the buffer may be checked under one of CONDITIONS.
   3428 
   3429 Read-only buffers may never be checked automatically.
   3430 
   3431 If CONDITIONS are given, determine whether syntax may be checked
   3432 under at least one of them, according to
   3433 `flycheck-check-syntax-automatically'."
   3434   (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p)))
   3435        (file-exists-p default-directory)
   3436        (or (not conditions)
   3437            (seq-some
   3438             (lambda (condition)
   3439               (memq condition flycheck-check-syntax-automatically))
   3440             conditions))))
   3441 
   3442 (defvar-local flycheck--idle-trigger-timer nil
   3443   "Timer used to trigger a syntax check after an idle delay.")
   3444 
   3445 (defvar-local flycheck--idle-trigger-conditions nil
   3446   "List of conditions under which an idle syntax check will be triggered.
   3447 This will be some subset of the allowable values for
   3448 `flycheck-check-syntax-automatically'.
   3449 
   3450 For example, if the user switches to a buffer and then makes an
   3451 edit, this list will have the values `idle-change' and
   3452 `idle-buffer-switch' in it, at least until the idle timer
   3453 expires.")
   3454 
   3455 (defun flycheck-buffer-automatically (&optional condition force-deferred)
   3456   "Automatically check syntax at CONDITION.
   3457 
   3458 Syntax is not checked if `flycheck-may-check-automatically'
   3459 returns nil for CONDITION.  (CONDITION may be a single condition
   3460 or a list of them.)
   3461 
   3462 The syntax check is deferred if FORCE-DEFERRED is non-nil, or if
   3463 `flycheck-must-defer-check' returns t."
   3464   (when (and flycheck-mode (if (listp condition)
   3465                                (apply #'flycheck-may-check-automatically
   3466                                       condition)
   3467                              (flycheck-may-check-automatically condition)))
   3468     (flycheck--clear-idle-trigger-timer)
   3469     (setq flycheck--idle-trigger-conditions nil)
   3470     (if (or force-deferred (flycheck-must-defer-check))
   3471         (flycheck-buffer-deferred)
   3472       (with-demoted-errors "Error while checking syntax automatically: %S"
   3473         (flycheck-buffer)))))
   3474 
   3475 (defun flycheck--clear-idle-trigger-timer ()
   3476   "Clear the idle trigger timer."
   3477   (when flycheck--idle-trigger-timer
   3478     (cancel-timer flycheck--idle-trigger-timer)
   3479     (setq flycheck--idle-trigger-timer nil)))
   3480 
   3481 (defun flycheck--handle-idle-trigger (buffer)
   3482   "Run a syntax check in BUFFER if appropriate.
   3483 This function is called by `flycheck--idle-trigger-timer'."
   3484   (let ((current-buffer (current-buffer)))
   3485     (when (buffer-live-p buffer)
   3486       (with-current-buffer buffer
   3487         (unless (or flycheck-buffer-switch-check-intermediate-buffers
   3488                     (eq buffer current-buffer))
   3489           (setq flycheck--idle-trigger-conditions
   3490                 (delq 'idle-buffer-switch
   3491                       flycheck--idle-trigger-conditions)))
   3492         (when flycheck--idle-trigger-conditions
   3493           (flycheck-buffer-automatically flycheck--idle-trigger-conditions)
   3494           (setq flycheck--idle-trigger-conditions nil))))))
   3495 
   3496 (defun flycheck-handle-change (beg end _len)
   3497   "Handle a buffer change between BEG and END.
   3498 
   3499 BEG and END mark the beginning and end of the change text.  _LEN
   3500 is ignored.
   3501 
   3502 Start a syntax check if a new line has been inserted into the
   3503 buffer."
   3504   ;; Save and restore the match data, as recommended in (elisp)Change Hooks
   3505   (save-match-data
   3506     (when flycheck-mode
   3507       (if (string-match-p (rx "\n") (buffer-substring beg end))
   3508           (flycheck-buffer-automatically 'new-line 'force-deferred)
   3509         (when (memq 'idle-change flycheck-check-syntax-automatically)
   3510           (flycheck--clear-idle-trigger-timer)
   3511           (cl-pushnew 'idle-change flycheck--idle-trigger-conditions)
   3512           (setq flycheck--idle-trigger-timer
   3513                 (run-at-time flycheck-idle-change-delay nil
   3514                              #'flycheck--handle-idle-trigger
   3515                              (current-buffer))))))))
   3516 
   3517 (defvar flycheck--last-buffer (current-buffer)
   3518   "The current buffer or the buffer that was previously current.
   3519 This is usually equal to the current buffer, unless the user just
   3520 switched buffers.  After a buffer switch, it is the previous
   3521 buffer.")
   3522 
   3523 (defun flycheck-handle-buffer-switch ()
   3524   "Handle a possible switch to another buffer.
   3525 
   3526 If a buffer switch actually happened, schedule a syntax check."
   3527   ;; Switching buffers here is weird, but unfortunately necessary.  It
   3528   ;; turns out that `with-temp-buffer' triggers
   3529   ;; `buffer-list-update-hook' twice, and the value of
   3530   ;; `current-buffer' is bogus in one of those triggers (the one just
   3531   ;; after the temp buffer is killed).  If we rely on the bogus value,
   3532   ;; Flycheck will think that the user is switching back and forth
   3533   ;; between different buffers during the `with-temp-buffer' call
   3534   ;; (note: two different normal buffers, not the current buffer and
   3535   ;; the temp buffer!), and that would trigger spurious syntax checks.
   3536   ;; It seems that reading (window-buffer) gets us the correct current
   3537   ;; buffer in all important real-life situations (although it doesn't
   3538   ;; necessarily catch uses of `set-buffer').
   3539   (with-current-buffer (window-buffer)
   3540     (unless (or (equal flycheck--last-buffer (current-buffer))
   3541                 ;; Don't bother keeping track of changes to and from
   3542                 ;; the minibuffer, as they will never require us to
   3543                 ;; run a syntax check.
   3544                 (minibufferp))
   3545       (setq flycheck--last-buffer (current-buffer))
   3546       (when (and flycheck-mode
   3547                  (memq 'idle-buffer-switch flycheck-check-syntax-automatically))
   3548         (flycheck--clear-idle-trigger-timer)
   3549         (cl-pushnew 'idle-buffer-switch flycheck--idle-trigger-conditions)
   3550         (setq flycheck--idle-trigger-timer
   3551               (run-at-time flycheck-idle-buffer-switch-delay nil
   3552                            #'flycheck--handle-idle-trigger
   3553                            (current-buffer)))))))
   3554 
   3555 (defun flycheck-handle-save ()
   3556   "Handle a save of the buffer."
   3557   (flycheck-buffer-automatically 'save))
   3558 
   3559 
   3560 ;;; Deferred syntax checking
   3561 (defvar-local flycheck-deferred-syntax-check nil
   3562   "If non-nil, a deferred syntax check is pending.")
   3563 
   3564 (defun flycheck-must-defer-check ()
   3565   "Determine whether the syntax check has to be deferred.
   3566 
   3567 A check has to be deferred if the buffer is not visible, or if the buffer is
   3568 currently being reverted.
   3569 
   3570 Return t if the check is to be deferred, or nil otherwise."
   3571   (or (not (get-buffer-window))
   3572       ;; We defer the syntax check if Flycheck is already running, to
   3573       ;; immediately start a new syntax check after the current one finished,
   3574       ;; because the result of the current check will most likely be outdated by
   3575       ;; the time it is finished.
   3576       (flycheck-running-p)
   3577       ;; We must defer checks while a buffer is being reverted, to avoid race
   3578       ;; conditions while the buffer contents are being restored.
   3579       revert-buffer-in-progress-p))
   3580 
   3581 (defun flycheck-deferred-check-p ()
   3582   "Determine whether the current buffer has a deferred check.
   3583 
   3584 Return t if so, or nil otherwise."
   3585   flycheck-deferred-syntax-check)
   3586 
   3587 (defun flycheck-buffer-deferred ()
   3588   "Defer syntax check for the current buffer."
   3589   (setq flycheck-deferred-syntax-check t))
   3590 
   3591 (defun flycheck-clean-deferred-check ()
   3592   "Clean a deferred syntax checking state."
   3593   (setq flycheck-deferred-syntax-check nil))
   3594 
   3595 (defun flycheck-perform-deferred-syntax-check ()
   3596   "Perform the deferred syntax check."
   3597   (when (flycheck-deferred-check-p)
   3598     (flycheck-clean-deferred-check)
   3599     (flycheck-buffer-automatically)))
   3600 
   3601 
   3602 ;;; Syntax checking in all buffers
   3603 (defun flycheck-may-enable-mode ()
   3604   "Determine whether Flycheck mode may be enabled.
   3605 
   3606 Flycheck mode is not enabled for
   3607 
   3608 - the minibuffer,
   3609 - `fundamental-mode'
   3610 - major modes whose `mode-class' property is `special',
   3611 - ephemeral buffers (see `flycheck-ephemeral-buffer-p'),
   3612 - encrypted buffers (see `flycheck-encrypted-buffer-p'),
   3613 - remote files (see `file-remote-p'),
   3614 - and major modes excluded by `flycheck-global-modes'.
   3615 
   3616 Return non-nil if Flycheck mode may be enabled, and nil
   3617 otherwise."
   3618   (and (pcase flycheck-global-modes
   3619          ;; Whether `major-mode' is disallowed by `flycheck-global-modes'
   3620          (`t t)
   3621          (`(not . ,modes) (not (memq major-mode modes)))
   3622          (modes (memq major-mode modes)))
   3623        (not (or (minibufferp)
   3624                 (eq major-mode 'fundamental-mode)
   3625                 (eq (get major-mode 'mode-class) 'special)
   3626                 (flycheck-ephemeral-buffer-p)
   3627                 (flycheck-encrypted-buffer-p)
   3628                 (and (buffer-file-name)
   3629                      (file-remote-p (buffer-file-name) 'method))))))
   3630 
   3631 (defun flycheck-mode-on-safe ()
   3632   "Enable command `flycheck-mode' if it is safe to do so.
   3633 
   3634 Command `flycheck-mode' is only enabled if
   3635 `flycheck-may-enable-mode' returns a non-nil result."
   3636   (when (flycheck-may-enable-mode)
   3637     (flycheck-mode)))
   3638 
   3639 ;;;###autoload
   3640 (define-globalized-minor-mode global-flycheck-mode flycheck-mode
   3641   flycheck-mode-on-safe
   3642   :init-value nil
   3643   :group 'flycheck)
   3644 
   3645 (defun flycheck-global-teardown (&optional ignore-local)
   3646   "Teardown Flycheck in all buffers.
   3647 
   3648 Completely clear the whole Flycheck state in all buffers, stop
   3649 all running checks, remove all temporary files, and empty all
   3650 variables of Flycheck.
   3651 
   3652 Also remove global hooks.  (If optional argument IGNORE-LOCAL is
   3653 non-nil, then only do this and skip per-buffer teardown.)"
   3654   (unless ignore-local
   3655     (dolist (buffer (buffer-list))
   3656       (when (buffer-live-p buffer)
   3657         (with-current-buffer buffer
   3658           (when flycheck-mode
   3659             (flycheck-teardown 'ignore-global))))))
   3660   (remove-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
   3661 
   3662 ;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any
   3663 ;; pending temporary files.
   3664 (add-hook 'kill-emacs-hook #'flycheck-global-teardown)
   3665 
   3666 
   3667 ;;; Errors from syntax checks
   3668 (cl-defstruct (flycheck-error
   3669                (:constructor nil)
   3670                (:constructor
   3671                 flycheck-error-new
   3672                 (&key
   3673                  line column end-line end-column
   3674                  buffer checker filename message level id group
   3675                  &aux (-end-line end-line) (-end-column end-column)))
   3676                (:constructor
   3677                 flycheck-error-new-at
   3678                 (line
   3679                  column
   3680                  &optional level message
   3681                  &key end-line end-column checker id group
   3682                  (filename (buffer-file-name)) (buffer (current-buffer))
   3683                  &aux (-end-line end-line) (-end-column end-column)))
   3684                (:constructor
   3685                 flycheck-error-new-at-pos
   3686                 (pos
   3687                  &optional level message
   3688                  &key end-pos checker id group
   3689                  (filename (buffer-file-name)) (buffer (current-buffer))
   3690                  &aux
   3691                  ((line . column)
   3692                   (if pos (flycheck-line-column-at-pos pos)
   3693                     '(nil . nil)))
   3694                  ((-end-line . -end-column)
   3695                   (if end-pos (flycheck-line-column-at-pos end-pos)
   3696                     '(nil . nil))))))
   3697   "Structure representing an error reported by a syntax checker.
   3698 Slots:
   3699 
   3700 `buffer'
   3701      The buffer that the error was reported for, as buffer object.
   3702 
   3703 `checker'
   3704      The syntax checker which reported this error, as symbol.
   3705 
   3706 `filename'
   3707      The file name the error refers to, as string.
   3708 
   3709 `line'
   3710      The line on which the error starts, as number.
   3711 
   3712 `column' (optional)
   3713      The column at which the error starts, as number.
   3714 
   3715      For compatibility with external tools and unlike Emacs
   3716      itself (e.g. in Compile Mode) Flycheck uses _1-based_
   3717      columns: The first character on a line is column 1.
   3718 
   3719      Occasionally some tools try to proactively adapt to Emacs
   3720      and emit 0-based columns automatically.  In these cases, the
   3721      columns must be adjusted for Flycheck, see
   3722      `flycheck-increment-error-columns'.
   3723 
   3724      If nil, the whole line is highlighted.
   3725 
   3726 `end-line' (optional)
   3727     The line on which the error ends.  If nil, this is computed according to
   3728     `flycheck-highlighting-mode'.
   3729 
   3730 `end-column'
   3731     The column at which the error ends.  If nil, this is computed according to
   3732     `flycheck-highlighting-mode'.  Error intervals are right-open: the
   3733     end-column points to the first character not included in the error.  For
   3734     example, 1:1 is an empty range. and in \"line-number-at-pos\", the range
   3735     6:12 covers the word \"number\".
   3736 
   3737 `message' (optional)
   3738      The error message as a string, if any.
   3739 
   3740 `level'
   3741      The error level, as either `info', `warning' or `error'.
   3742 
   3743 `id' (optional)
   3744      An ID identifying the kind of error.
   3745 
   3746 `group' (optional)
   3747      A symbol identifying the group the error belongs to.
   3748 
   3749      Some tools will emit multiple errors that relate to the same
   3750      issue (e.g., lifetime errors in Rust).  All related errors
   3751      collected by a checker should have the same `group` value,
   3752      in order to be able to present them to the user.
   3753 
   3754      See `flycheck-related-errors`."
   3755   buffer checker filename line column message level id group
   3756   ;; The fields below are at the end of the record to preserve backwards
   3757   ;; compatibility; see https://github.com/flycheck/flycheck/pull/1400 and
   3758   ;; https://lists.gnu.org/archive/html/emacs-devel/2018-07/msg00436.html
   3759   -end-line -end-column)
   3760 
   3761 ;; These accessors are defined for backwards compatibility
   3762 ;; FIXME: Clean up once package.el learns how to recompile dependencies.
   3763 
   3764 (defun flycheck-error-end-line (err)
   3765   "Return the end line of a Flycheck error ERR."
   3766   (condition-case nil (flycheck-error--end-line err)
   3767     (args-out-of-range nil)))
   3768 
   3769 (defun flycheck-error-end-column (err)
   3770   "Return the end column of a Flycheck error ERR."
   3771   (condition-case nil (flycheck-error--end-column err)
   3772     (args-out-of-range nil)))
   3773 
   3774 (defun flycheck-error--set-end-line (err line)
   3775   "Set the end line of a Flycheck error ERR to LINE."
   3776   (condition-case nil (setf (flycheck-error--end-line err) line)
   3777     (args-out-of-range nil)))
   3778 
   3779 (defun flycheck-error--set-end-column (err column)
   3780   "Set the end column of a Flycheck error ERR to COLUMN."
   3781   (condition-case nil (setf (flycheck-error--end-column err) column)
   3782     (args-out-of-range nil)))
   3783 
   3784 (gv-define-simple-setter flycheck-error-end-line
   3785                          flycheck-error--set-end-line)
   3786 (gv-define-simple-setter flycheck-error-end-column
   3787                          flycheck-error--set-end-column)
   3788 
   3789 (defmacro flycheck-error-with-buffer (err &rest forms)
   3790   "Switch to the buffer of ERR and evaluate FORMS.
   3791 
   3792 If the buffer of ERR is not live, FORMS are not evaluated."
   3793   (declare (indent 1) (debug t))
   3794   `(when (buffer-live-p (flycheck-error-buffer ,err))
   3795      (with-current-buffer (flycheck-error-buffer ,err)
   3796        ,@forms)))
   3797 
   3798 (defun flycheck--exact-region (err)
   3799   "Get the region of ERR, if ERR specifies a range.
   3800 
   3801 Return a cons cell `(BEG . END)'.  If the input range is empty,
   3802 it is expanded to cover at least one character so that END is
   3803 always greater than BEG.  If ERR doesn't specify an end-column
   3804 return nil."
   3805   (if-let* ((line (flycheck-error-line err))
   3806             (column (flycheck-error-column err))
   3807             (end-line (or (flycheck-error-end-line err) line))
   3808             (end-column (flycheck-error-end-column err)))
   3809       ;; Ignoring fields speeds up calls to `line-end-position'.
   3810       (let* ((inhibit-field-text-motion t)
   3811              (beg (flycheck-line-column-to-position line column))
   3812              (end (flycheck-line-column-to-position end-line end-column)))
   3813         (cond
   3814          ((< beg end) (cons beg end))
   3815          ((= end (point-max)) (cons (1- end) end))
   3816          (t (cons end (1+ end)))))))
   3817 
   3818 (defun flycheck--line-region (pos)
   3819   "Get the line region of position POS.
   3820 
   3821 Return a cons cell `(BEG . END)' where BEG is the first
   3822 non-whitespace character on the line ERR refers to, and END the
   3823 end of the line."
   3824   (save-excursion
   3825     (goto-char pos)
   3826     (forward-line 0)
   3827     (let ((bol (point))
   3828           (end (line-end-position)))
   3829       ;; Move to the beginning of this line's indentation, similar to
   3830       ;; `back-to-indentation'
   3831       (skip-syntax-forward " " end)
   3832       (backward-prefix-chars)
   3833       ;; If the current line is blank, highlight it in full; if it's
   3834       ;; empty, include the previous line break character(s) to have
   3835       ;; any region at all (when called with 0, `line-end-position'
   3836       ;; gives us the end of the previous line).
   3837       (cons (if (eolp) (if (= bol end) (line-end-position 0) bol) (point))
   3838             end))))
   3839 
   3840 (defun flycheck--column-region (pos)
   3841   "Get the column region of position POS.
   3842 
   3843 Return a cons cell `(BEG . END)' where BEG is the character
   3844 before the column, and END the actual column."
   3845   (save-excursion
   3846     (goto-char pos)
   3847     ;; (eobp): No enough lines in the buffer
   3848     (if (eobp) (cons (1- (point-max)) (point-max))
   3849       (cons pos (1+ pos)))))
   3850 
   3851 (defun flycheck-bounds-of-thing-at-point (thing pos)
   3852   "Get the region of THING at position POS.
   3853 
   3854 THING is a understood by `thing-at-point'.
   3855 
   3856 Return a cons cell `(BEG . END)' where BEG is the beginning of
   3857 the THING at the column, and END the end of the THING."
   3858   (save-excursion
   3859     (goto-char pos)
   3860     (bounds-of-thing-at-point thing)))
   3861 
   3862 (defun flycheck--approximate-region (err mode)
   3863   "Compute the region of ERR based on MODE and ERR's line and column."
   3864   ;; Ignoring fields speeds up calls to `line-end-position'.
   3865   (let* ((inhibit-field-text-motion t)
   3866          (line (flycheck-error-line err))
   3867          (column (flycheck-error-column err))
   3868          (beg (flycheck-line-column-to-position line (or column 1))))
   3869     (if (or (null column)
   3870             (eq mode 'lines))
   3871         (flycheck--line-region beg)
   3872       (or (pcase mode
   3873             (`symbols
   3874              ;; Ensure that we're on a word or symbol.  See
   3875              ;; https://github.com/flycheck/flycheck/issues/1519
   3876              (and (<= (point-min) beg) (< beg (point-max))
   3877                   (memq (char-syntax (char-after beg)) '(?w ?_))
   3878                   (flycheck-bounds-of-thing-at-point 'symbol beg)))
   3879             (`sexps
   3880              (flycheck-bounds-of-thing-at-point 'sexp beg)))
   3881           (flycheck--column-region beg)))))
   3882 
   3883 (defun flycheck-error-region-for-mode (err mode)
   3884   "Get the region of ERR for the highlighting MODE.
   3885 
   3886 ERR is a Flycheck error.  If its position is fully specified, use
   3887 that to compute a region; otherwise, use MODE, as documented in
   3888 `flycheck-highlighting-mode'.  If MODE is nil, signal an error."
   3889   (flycheck-error-with-buffer err
   3890     (save-restriction
   3891       (widen)
   3892       (or (flycheck--exact-region err)
   3893           (flycheck--approximate-region err mode)))))
   3894 
   3895 (defun flycheck-error-pos (err)
   3896   "Get the buffer position of ERR.
   3897 
   3898 ERR is a Flycheck error whose position to get.
   3899 
   3900 The error position is the error column, or the first
   3901 non-whitespace character of the error line, if ERR has no error column."
   3902   (car (flycheck-error-region-for-mode
   3903         err flycheck-highlighting-mode)))
   3904 
   3905 (defun flycheck-error-format-snippet (err &optional max-length)
   3906   "Extract the text that ERR refers to from the buffer.
   3907 
   3908 Newlines and blanks are replaced by single spaces.  If ERR
   3909 doesn't include an end-position, return nil.
   3910 
   3911 MAX-LENGTH is how many characters to read from the buffer, at
   3912 most.  It defaults to 20."
   3913   (flycheck-error-with-buffer err
   3914     (save-restriction
   3915       (widen)
   3916       (pcase (flycheck--exact-region err)
   3917         (`(,beg . ,end)
   3918          (truncate-string-to-width
   3919           (replace-regexp-in-string
   3920            "\\s-+" " " (buffer-substring beg (min end (point-max))))
   3921           (or max-length 20) nil nil t))))))
   3922 
   3923 (defun flycheck-error-format-message-and-id (err &optional include-snippet)
   3924   "Format the message and id of ERR as human-readable string.
   3925 
   3926 If INCLUDE-SNIPPET is non-nil, prepend the message with a snippet
   3927 of the text that the error applies to (such text can only be
   3928 determined if the error contains a full span, not just a
   3929 beginning position)."
   3930   (let* ((id (flycheck-error-id err))
   3931          (fname (flycheck-error-filename err))
   3932          (other-file-p (and fname (not (equal fname (buffer-file-name))))))
   3933     (concat (and other-file-p (format "In %S:\n" (file-relative-name fname)))
   3934             (and include-snippet
   3935                  (when-let* ((snippet (flycheck-error-format-snippet err)))
   3936                    (format-message "`%s': " snippet)))
   3937             (or (flycheck-error-message err)
   3938                 (format "Unknown %S" (flycheck-error-level err)))
   3939             (and id (format " [%s]" id)))))
   3940 
   3941 (defun flycheck-error-format-position (err)
   3942   "Format the position of ERR as a human-readable string."
   3943   (let ((line (flycheck-error-line err))
   3944         (column (flycheck-error-column err))
   3945         (end-line (flycheck-error-end-line err))
   3946         (end-column (flycheck-error-end-column err)))
   3947     (if (and line column)
   3948         (if (or (null end-line) (equal line end-line))
   3949             (if (or (null end-column) (equal column (1- end-column)))
   3950                 (format "%d:%d" line column)
   3951               (format "%d:%d-%d" line column end-column))
   3952           (format "(%d:%d)-(%d:%d)" line column end-line end-column))
   3953       (if (or (null end-line) (equal line end-line))
   3954           (format "%d" line)
   3955         (format "%d-%d" line end-line)))))
   3956 
   3957 (defun flycheck-error-format (err &optional with-file-name)
   3958   "Format ERR as human-readable string, optionally WITH-FILE-NAME.
   3959 
   3960 Return a string that represents the given ERR.  If WITH-FILE-NAME
   3961 is given and non-nil, include the file-name as well, otherwise
   3962 omit it."
   3963   (let* ((level (symbol-name (flycheck-error-level err)))
   3964          (checker (symbol-name (flycheck-error-checker err)))
   3965          (format `(,@(when with-file-name
   3966                        (list (flycheck-error-filename err) ":"))
   3967                    ,(flycheck-error-format-position err) ":"
   3968                    ,level ": "
   3969                    ,(flycheck-error-format-message-and-id err)
   3970                    " (" ,checker ")")))
   3971     (apply #'concat format)))
   3972 
   3973 (defun flycheck-error-< (err1 err2)
   3974   "Determine whether ERR1 is less than ERR2 by location."
   3975   (let ((l1 (flycheck-error-line err1))
   3976         (l2 (flycheck-error-line err2)))
   3977     (if (/= l1 l2)
   3978         (< l1 l2)
   3979       (let ((c1 (or (flycheck-error-column err1) 1))
   3980             (c2 (or (flycheck-error-column err2) 1)))
   3981         (if (/= c1 c2)
   3982             (< c1 c2)
   3983           (let ((el1 (or (flycheck-error-end-line err1) l1))
   3984                 (el2 (or (flycheck-error-end-line err2) l2)))
   3985             (if (/= el1 el2)
   3986                 (< el1 el2)
   3987               (let ((cl1 (or (flycheck-error-end-column err1) 1))
   3988                     (cl2 (or (flycheck-error-end-column err2) 1)))
   3989                 (< cl1 cl2)))))))))
   3990 
   3991 (defun flycheck-error-level-< (err1 err2)
   3992   "Determine whether ERR1 is less than ERR2 by error level.
   3993 
   3994 Like `flycheck-error-<', but compares by error level severity
   3995 first.  Levels of the same severity are compared by name."
   3996   (let* ((level1 (flycheck-error-level err1))
   3997          (level2 (flycheck-error-level err2))
   3998          (severity1 (flycheck-error-level-severity level1))
   3999          (severity2 (flycheck-error-level-severity level2)))
   4000     (cond
   4001      ((= severity1 severity2)
   4002       (if (string= level1 level2)
   4003           (flycheck-error-< err1 err2)
   4004         (string< level1 level2)))
   4005      (t (< severity1 severity2)))))
   4006 
   4007 (defun flycheck-assert-error-list-p (errors)
   4008   "Assert that all items in ERRORS are of `flycheck-error' type.
   4009 
   4010 Signal an error if any item in ERRORS is not a `flycheck-error'
   4011 object, as by `flycheck-error-p'.  Otherwise return ERRORS
   4012 again."
   4013   (unless (listp errors)
   4014     (signal 'wrong-type-argument (list 'listp errors)))
   4015   (dolist (err errors)
   4016     (unless (flycheck-error-p err)
   4017       (signal 'wrong-type-argument (list 'flycheck-error-p err))))
   4018   errors)
   4019 
   4020 
   4021 ;;; Errors in the current buffer
   4022 (defvar-local flycheck-current-errors nil
   4023   "A list of all errors and warnings in the current buffer.")
   4024 
   4025 (defun flycheck-report-current-errors (errors)
   4026   "Report ERRORS in the current buffer.
   4027 
   4028 Add ERRORS to `flycheck-current-errors' and process each error
   4029 with `flycheck-process-error-functions'."
   4030   (setq flycheck-current-errors (append errors flycheck-current-errors))
   4031   (overlay-recenter (point-max))
   4032   ;; We can't use `seq-sort-by' because it's not in Emacs 25's built-in `seq',
   4033   ;; and installing an updated version doesn't help (this is a package.el bug;
   4034   ;; see https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg01974.html).
   4035   (seq-do (lambda (err)
   4036             (run-hook-with-args-until-success 'flycheck-process-error-functions
   4037                                               err))
   4038           (seq-sort (lambda (e1 e2)
   4039                       (< (flycheck-error-line e1) (flycheck-error-line e2)))
   4040                     errors)))
   4041 
   4042 (defun flycheck-clear-errors ()
   4043   "Remove all error information from the current buffer."
   4044   (setq flycheck-current-errors nil)
   4045   (flycheck-report-status 'not-checked))
   4046 
   4047 (defun flycheck-fill-and-expand-error-file-names (errors directory)
   4048   "Fill and expand file names in ERRORS relative to DIRECTORY.
   4049 
   4050 Expand all file names of ERRORS against DIRECTORY.  If the file
   4051 name of an error is nil fill in the result of function
   4052 `buffer-file-name' in the current buffer.
   4053 
   4054 Return ERRORS, modified in-place."
   4055   (seq-do (lambda (err)
   4056             (setf (flycheck-error-filename err)
   4057                   (if-let (filename (flycheck-error-filename err))
   4058                       (expand-file-name filename directory)
   4059                     (buffer-file-name))))
   4060           errors)
   4061   errors)
   4062 
   4063 (defun flycheck-relevant-error-other-file-p (err)
   4064   "Determine whether ERR is a relevant error for another file."
   4065   (let ((file-name (flycheck-error-filename err)))
   4066     (and file-name
   4067          flycheck-relevant-error-other-file-show
   4068          (or (null buffer-file-name)
   4069              (not (flycheck-same-files-p buffer-file-name file-name)))
   4070          (<= (flycheck-error-level-severity
   4071               flycheck-relevant-error-other-file-minimum-level)
   4072              (flycheck-error-level-severity (flycheck-error-level err))))))
   4073 
   4074 (defun flycheck-relevant-error-p (err)
   4075   "Determine whether ERR is relevant for the current buffer.
   4076 
   4077 Return t if ERR may be shown for the current buffer, or nil
   4078 otherwise."
   4079   (flycheck-error-with-buffer err
   4080     (let ((file-name (flycheck-error-filename err))
   4081           (message (flycheck-error-message err)))
   4082       (and
   4083        (or
   4084         ;; Neither the error nor buffer have a file name
   4085         (and (not file-name) (not buffer-file-name))
   4086         ;; Both have files, and they match
   4087         (and buffer-file-name file-name
   4088              (flycheck-same-files-p file-name buffer-file-name))
   4089         ;; This is a significant error from another file
   4090         (flycheck-relevant-error-other-file-p err))
   4091        message
   4092        (not (string-empty-p message))
   4093        ;; Errors without line numbers are discarded.  If a linter
   4094        ;; reports relevant errors without line numbers, use
   4095        ;; `flycheck-fill-empty-line-numbers' as the checker's
   4096        ;; `:error-filter' to set them to line 0.
   4097        (flycheck-error-line err)))))
   4098 
   4099 (defun flycheck-relevant-errors (errors)
   4100   "Filter the relevant errors from ERRORS.
   4101 
   4102 Return a list of all errors that are relevant for their
   4103 corresponding buffer."
   4104   (seq-filter #'flycheck-relevant-error-p errors))
   4105 
   4106 (defun flycheck-related-errors (err &optional error-set)
   4107   "Get all the errors that are in the same group as ERR.
   4108 
   4109 Return a list of all errors (from ERROR-SET) that have the same
   4110 `flycheck-error-group' as ERR, including ERR itself.
   4111 
   4112 If ERROR-SET is nil, `flycheck-current-errors' is used instead."
   4113   (let ((group (flycheck-error-group err))
   4114         (checker (flycheck-error-checker err)))
   4115     (if group
   4116         (seq-filter (lambda (e)
   4117                       (and (eq (flycheck-error-checker e) checker)
   4118                            (eq (flycheck-error-group e) group)))
   4119                     (or error-set flycheck-current-errors))
   4120       (list err))))
   4121 
   4122 
   4123 ;;; Status reporting for the current buffer
   4124 (defvar-local flycheck-last-status-change 'not-checked
   4125   "The last status change in the current buffer.")
   4126 
   4127 (defun flycheck-report-failed-syntax-check (&optional status)
   4128   "Report a failed Flycheck syntax check with STATUS.
   4129 
   4130 STATUS is a status symbol for `flycheck-report-status',
   4131 defaulting to `errored'.
   4132 
   4133 Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and
   4134 report an error STATUS."
   4135   (flycheck-clear)
   4136   (setq flycheck-current-syntax-check nil)
   4137   (run-hooks 'flycheck-syntax-check-failed-hook)
   4138   (flycheck-report-status (or status 'errored)))
   4139 
   4140 (defun flycheck-report-status (status)
   4141   "Report Flycheck STATUS.
   4142 
   4143 STATUS is one of the following symbols:
   4144 
   4145 `not-checked'
   4146      The current buffer was not checked.
   4147 
   4148 `no-checker'
   4149      Automatic syntax checker selection did not find a suitable
   4150      syntax checker.
   4151 
   4152 `running'
   4153      A syntax check is now running in the current buffer.
   4154 
   4155 `errored'
   4156      The current syntax check has errored.
   4157 
   4158 `finished'
   4159      The current syntax check was finished normally.
   4160 
   4161 `interrupted'
   4162      The current syntax check was interrupted.
   4163 
   4164 `suspicious'
   4165      The last syntax check had a suspicious result.
   4166 
   4167 Set `flycheck-last-status-change' and call
   4168 `flycheck-status-changed-functions' with STATUS.  Afterwards
   4169 refresh the mode line."
   4170   (setq flycheck-last-status-change status)
   4171   (run-hook-with-args 'flycheck-status-changed-functions status)
   4172   (force-mode-line-update))
   4173 
   4174 (defun flycheck-mode-line-status-text (&optional status)
   4175   "Get a text describing STATUS for use in the mode line.
   4176 
   4177 STATUS defaults to `flycheck-last-status-change' if omitted or
   4178 nil."
   4179   (let* ((current-status (or status flycheck-last-status-change))
   4180          (indicator (pcase current-status
   4181                       (`not-checked "")
   4182                       (`no-checker "-")
   4183                       (`running "*")
   4184                       (`errored "!")
   4185                       (`finished
   4186                        (let-alist (flycheck-count-errors flycheck-current-errors)
   4187                          (if (or .error .warning)
   4188                              (format ":%s|%s" (or .error 0) (or .warning 0))
   4189                            flycheck-mode-success-indicator)))
   4190                       (`interrupted ".")
   4191                       (`suspicious "?")))
   4192          (face (when flycheck-mode-line-color
   4193                  (pcase current-status
   4194                    (`errored 'error)
   4195                    (`finished
   4196                     (let-alist (flycheck-count-errors flycheck-current-errors)
   4197                       (if (or .error .warning) 'error 'success))))))
   4198          (text (format " %s%s" flycheck-mode-line-prefix indicator)))
   4199     (when face
   4200       (setq text (propertize text 'face face)))
   4201     text))
   4202 
   4203 
   4204 ;;; Error levels
   4205 (defun flycheck-make-margin-spec (margin-str face)
   4206   "Make a display spec to indicate errors in the margins.
   4207 
   4208 Returns MARGIN-STR with FACE applied."
   4209   (propertize margin-str 'face `(,face default)))
   4210 
   4211 (defconst flycheck-default-margin-str "»"
   4212   "String used to indicate errors in the margins.")
   4213 
   4214 (defconst flycheck-default-margin-continuation-str "⋮"
   4215   "String used to indicate continuation lines in the margins.")
   4216 
   4217 ;;;###autoload
   4218 (defun flycheck-define-error-level (level &rest properties)
   4219   "Define a new error LEVEL with PROPERTIES.
   4220 
   4221 The following PROPERTIES constitute an error level:
   4222 
   4223 `:severity SEVERITY'
   4224      A number denoting the severity of this level.  The higher
   4225      the number, the more severe is this level compared to other
   4226      levels.  Defaults to 0; info is -10, warning is 10, and
   4227      error is 100.
   4228 
   4229      The severity is used by `flycheck-error-level-<' to
   4230      determine the ordering of errors according to their levels.
   4231 
   4232 `:compilation-level LEVEL'
   4233 
   4234      A number indicating the broad class of messages that errors
   4235      at this level belong to: one of 0 (info), 1 (warning), or
   4236      2 or nil (error).  Defaults to nil.
   4237 
   4238      This is used by `flycheck-checker-pattern-to-error-regexp'
   4239      to map error levels into `compilation-mode''s hierarchy and
   4240      to get proper highlighting of errors in `compilation-mode'.
   4241 
   4242 `:overlay-category CATEGORY'
   4243      A symbol denoting the overlay category to use for error
   4244      highlight overlays for this level.  See Info
   4245      node `(elisp)Overlay Properties' for more information about
   4246      overlay categories.
   4247 
   4248      A category for an error level overlay should at least define
   4249      the `face' property, for error highlighting.  Another useful
   4250      property for error level categories is `priority', to
   4251      influence the stacking of multiple error level overlays.
   4252 
   4253 `:fringe-bitmap BITMAPS'
   4254      A fringe bitmap symbol denoting the bitmap to use for fringe
   4255      indicators for this level, or a cons of two bitmaps (one for
   4256      narrow fringes and one for wide fringes).  See Info node
   4257      `(elisp)Fringe Bitmaps' for more information about fringe
   4258      bitmaps, including a list of built-in fringe bitmaps.
   4259 
   4260 `:fringe-face FACE'
   4261      A face symbol denoting the face to use for fringe indicators
   4262      for this level.
   4263 
   4264 `:margin-spec SPEC'
   4265      A display specification indicating what to display in the
   4266      margin when `flycheck-indication-mode' is `left-margin' or
   4267      `right-margin'.  See Info node `(elisp)Displaying in the
   4268      Margins'.  If omitted, Flycheck generates an image spec from
   4269      the fringe bitmap.
   4270 
   4271 `:error-list-face FACE'
   4272      A face symbol denoting the face to use for messages of this
   4273      level in the error list.  See `flycheck-list-errors'."
   4274   (declare (indent 1))
   4275   (setf (get level 'flycheck-error-level) t)
   4276   (setf (get level 'flycheck-error-severity)
   4277         (or (plist-get properties :severity) 0))
   4278   (setf (get level 'flycheck-compilation-level)
   4279         (plist-get properties :compilation-level))
   4280   (setf (get level 'flycheck-overlay-category)
   4281         (plist-get properties :overlay-category))
   4282   (setf (get level 'flycheck-fringe-bitmaps)
   4283         (let ((bitmap (plist-get properties :fringe-bitmap)))
   4284           (if (consp bitmap) bitmap (cons bitmap bitmap))))
   4285   ;; Kept for compatibility
   4286   (setf (get level 'flycheck-fringe-bitmap-double-arrow)
   4287         (car (get level 'flycheck-fringe-bitmaps)))
   4288   (setf (get level 'flycheck-fringe-face)
   4289         (plist-get properties :fringe-face))
   4290   (setf (get level 'flycheck-margin-spec)
   4291         (or (plist-get properties :margin-spec)
   4292             (flycheck-make-margin-spec
   4293              flycheck-default-margin-str
   4294              (or (get level 'flycheck-fringe-face) 'default))))
   4295   (setf (get level 'flycheck-margin-continuation)
   4296         (flycheck-make-margin-spec
   4297          flycheck-default-margin-continuation-str
   4298          (or (get level 'flycheck-fringe-face) 'default)))
   4299   (setf (get level 'flycheck-error-list-face)
   4300         (plist-get properties :error-list-face)))
   4301 
   4302 (defun flycheck-error-level-p (level)
   4303   "Determine whether LEVEL is a Flycheck error level."
   4304   (get level 'flycheck-error-level))
   4305 
   4306 (defun flycheck-error-level-severity (level)
   4307   "Get the numeric severity of LEVEL."
   4308   (or (get level 'flycheck-error-severity) 0))
   4309 
   4310 (defun flycheck-error-level-compilation-level (level)
   4311   "Get the compilation level for LEVEL."
   4312   (get level 'flycheck-compilation-level))
   4313 
   4314 (defun flycheck-error-level-overlay-category (level)
   4315   "Get the overlay category for LEVEL."
   4316   (get level 'flycheck-overlay-category))
   4317 
   4318 (defun flycheck-error-level-margin-spec (level)
   4319   "Get the margin spec for LEVEL."
   4320   (get level 'flycheck-margin-spec))
   4321 
   4322 (defun flycheck-error-level-margin-continuation-spec (level)
   4323   "Get the margin continuation spec for LEVEL."
   4324   (get level 'flycheck-margin-continuation))
   4325 
   4326 (defun flycheck-error-level-fringe-bitmap (level &optional hi-res)
   4327   "Get the fringe bitmap for LEVEL.
   4328 
   4329 Optional argument HI-RES non-nil means that the returned bitmap
   4330 will be the high resolution version."
   4331   (let ((bitmaps (get level 'flycheck-fringe-bitmaps)))
   4332     (if hi-res (cdr bitmaps) (car bitmaps))))
   4333 
   4334 (defun flycheck-error-level-fringe-face (level)
   4335   "Get the fringe face for LEVEL."
   4336   (get level 'flycheck-fringe-face))
   4337 
   4338 (defun flycheck-error-level-error-list-face (level)
   4339   "Get the error list face for LEVEL."
   4340   (get level 'flycheck-error-list-face))
   4341 
   4342 (defun flycheck-error-level-make-indicator (level side &optional continuation)
   4343   "Create the fringe or margin icon for LEVEL at SIDE.
   4344 
   4345 Return a propertized string that shows an indicator according
   4346 to LEVEL and the given fringe or margin SIDE.
   4347 
   4348 LEVEL is a Flycheck error level defined with
   4349 `flycheck-define-error-level', and SIDE is either `left-fringe',
   4350 `right-fringe', `left-margin', or `right-margin'.
   4351 
   4352 CONTINUATION indicates which fringe bitmap or margin spec to use:
   4353 either the `:fringe-bitmap' and `:margin-spec' properties of
   4354 LEVEL when CONTINUATION is nil or omitted, or bitmaps and specs
   4355 indicating an error spanning more than one line.
   4356 
   4357 Return a propertized string representing the fringe icon,
   4358 intended for use as `before-string' of an overlay to actually
   4359 show the indicator."
   4360   (propertize
   4361    "!" 'display
   4362    (pcase side
   4363      ((or `left-fringe `right-fringe)
   4364       (list side
   4365             (if continuation 'flycheck-fringe-bitmap-continuation
   4366               (let* ((fringe-width
   4367                       (pcase side
   4368                         (`left-fringe (car (window-fringes)))
   4369                         (`right-fringe (cadr (window-fringes)))))
   4370                      (high-res (>= fringe-width 16)))
   4371                 (flycheck-error-level-fringe-bitmap level high-res)))
   4372             (flycheck-error-level-fringe-face level)))
   4373      ((or `left-margin `right-margin)
   4374       `((margin ,side)
   4375         ,(or (if continuation
   4376                  (flycheck-error-level-margin-continuation-spec level)
   4377                (flycheck-error-level-margin-spec level))
   4378              "")))
   4379      (_ (error "Invalid fringe side: %S" side)))))
   4380 
   4381 (define-obsolete-function-alias
   4382   'flycheck-error-level-make-fringe-icon
   4383   'flycheck-error-level-make-indicator
   4384   "33")
   4385 
   4386 
   4387 ;;; Built-in error levels
   4388 (defconst flycheck-fringe-bitmap-double-arrow
   4389   [#b11011000
   4390    #b01101100
   4391    #b00110110
   4392    #b00011011
   4393    #b00110110
   4394    #b01101100
   4395    #b11011000]
   4396   "Bitmaps used to indicate errors in the left fringes.")
   4397 
   4398 (defconst flycheck-fringe-bitmap-double-left-arrow
   4399   [#b00011011
   4400    #b00110110
   4401    #b01101100
   4402    #b11011000
   4403    #b01101100
   4404    #b00110110
   4405    #b00011011]
   4406   "Bitmaps used to indicate errors in the right fringes.")
   4407 
   4408 (defconst flycheck-fringe-bitmap-double-arrow-hi-res
   4409   [#b1111001111000000
   4410    #b0111100111100000
   4411    #b0011110011110000
   4412    #b0001111001111000
   4413    #b0000111100111100
   4414    #b0000011110011110
   4415    #b0000011110011110
   4416    #b0000111100111100
   4417    #b0001111001111000
   4418    #b0011110011110000
   4419    #b0111100111100000
   4420    #b1111001111000000]
   4421   "High-resolution bitmap used to indicate errors in the left fringes.")
   4422 
   4423 (defconst flycheck-fringe-bitmap-double-left-arrow-hi-res
   4424   [#b0000001111001111
   4425    #b0000011110011110
   4426    #b0000111100111100
   4427    #b0001111001111000
   4428    #b0011110011110000
   4429    #b0111100111100000
   4430    #b0111100111100000
   4431    #b0011110011110000
   4432    #b0001111001111000
   4433    #b0000111100111100
   4434    #b0000011110011110
   4435    #b0000001111001111]
   4436   "High-resolution bitmap used to indicate errors in the right fringes.")
   4437 
   4438 (defconst flycheck-fringe-bitmap-continuation
   4439   [#b1000000010000000
   4440    #b0010000000100000
   4441    #b0000100000001000
   4442    #b0000001000000010]
   4443   "Bitmap used to indicate continuation lines in the fringes.")
   4444 
   4445 (when (fboundp 'define-fringe-bitmap) ;; #ifdef HAVE_WINDOW_SYSTEM
   4446   (define-fringe-bitmap
   4447     'flycheck-fringe-bitmap-double-arrow
   4448     flycheck-fringe-bitmap-double-arrow)
   4449   (define-fringe-bitmap
   4450     'flycheck-fringe-bitmap-double-arrow-hi-res
   4451     flycheck-fringe-bitmap-double-arrow-hi-res
   4452     nil 16)
   4453   (define-fringe-bitmap
   4454     'flycheck-fringe-bitmap-double-left-arrow
   4455     flycheck-fringe-bitmap-double-left-arrow)
   4456   (define-fringe-bitmap
   4457     'flycheck-fringe-bitmap-double-left-arrow-hi-res
   4458     flycheck-fringe-bitmap-double-left-arrow-hi-res
   4459     nil 16)
   4460   (define-fringe-bitmap
   4461     'flycheck-fringe-bitmap-continuation
   4462     flycheck-fringe-bitmap-continuation
   4463     nil 16 '(top repeat)))
   4464 
   4465 (defun flycheck-redefine-standard-error-levels
   4466     (&optional margin-str fringe-bitmap)
   4467   "Redefine Flycheck's standard error levels.
   4468 
   4469 This is useful to change the character drawn in the
   4470 margins (MARGIN-STR, a string) or the bitmap drawn in the
   4471 fringes (FRINGE-BITMAP, a fringe bitmap symbol or a cons of such
   4472 symbols, as in `flycheck-define-error-level')."
   4473   (unless margin-str
   4474     (setq margin-str flycheck-default-margin-str))
   4475 
   4476   (unless fringe-bitmap
   4477     (setq fringe-bitmap
   4478           (cons 'flycheck-fringe-bitmap-double-arrow
   4479                 'flycheck-fringe-bitmap-double-arrow-hi-res)))
   4480 
   4481   (setf (get 'flycheck-error-overlay 'face) 'flycheck-error)
   4482   (setf (get 'flycheck-error-overlay 'priority) 110)
   4483 
   4484   (flycheck-define-error-level 'error
   4485     :severity 100
   4486     :compilation-level 2
   4487     :overlay-category 'flycheck-error-overlay
   4488     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-error)
   4489     :fringe-bitmap fringe-bitmap
   4490     :fringe-face 'flycheck-fringe-error
   4491     :error-list-face 'flycheck-error-list-error)
   4492 
   4493   (setf (get 'flycheck-warning-overlay 'face) 'flycheck-warning)
   4494   (setf (get 'flycheck-warning-overlay 'priority) 100)
   4495 
   4496   (flycheck-define-error-level 'warning
   4497     :severity 10
   4498     :compilation-level 1
   4499     :overlay-category 'flycheck-warning-overlay
   4500     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-warning)
   4501     :fringe-bitmap fringe-bitmap
   4502     :fringe-face 'flycheck-fringe-warning
   4503     :error-list-face 'flycheck-error-list-warning)
   4504 
   4505   (setf (get 'flycheck-info-overlay 'face) 'flycheck-info)
   4506   (setf (get 'flycheck-info-overlay 'priority) 90)
   4507 
   4508   (flycheck-define-error-level 'info
   4509     :severity -10
   4510     :compilation-level 0
   4511     :overlay-category 'flycheck-info-overlay
   4512     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-info)
   4513     :fringe-bitmap fringe-bitmap
   4514     :fringe-face 'flycheck-fringe-info
   4515     :error-list-face 'flycheck-error-list-info))
   4516 
   4517 (flycheck-redefine-standard-error-levels)
   4518 
   4519 
   4520 ;;; Error filtering
   4521 (defun flycheck-filter-errors (errors checker)
   4522   "Filter ERRORS from CHECKER.
   4523 
   4524 Apply the error filter of CHECKER to ERRORs and return the
   4525 result.  If CHECKER has no error filter, fall back to
   4526 `flycheck-sanitize-errors'."
   4527   (let ((filter (or (flycheck-checker-get checker 'error-filter)
   4528                     #'flycheck-sanitize-errors)))
   4529     (funcall filter errors)))
   4530 
   4531 (defun flycheck-sanitize-errors (errors)
   4532   "Sanitize ERRORS.
   4533 
   4534 Sanitize ERRORS by trimming leading and trailing whitespace in
   4535 all error messages, and by replacing 0 columns and empty error
   4536 messages with nil.
   4537 
   4538 Returns sanitized ERRORS."
   4539   (dolist (err errors)
   4540     (flycheck-error-with-buffer err
   4541       (let ((message (flycheck-error-message err))
   4542             (id (flycheck-error-id err)))
   4543         (when message
   4544           (setq message (string-trim message))
   4545           (setf (flycheck-error-message err)
   4546                 (if (string-empty-p message) nil message)))
   4547         (when (and id (string-empty-p id))
   4548           (setf (flycheck-error-id err) nil))
   4549         (when (eq (flycheck-error-column err) 0)
   4550           (setf (flycheck-error-column err) nil))
   4551         (when (eq (flycheck-error-end-column err) 0)
   4552           (setf (flycheck-error-end-column err) nil)))))
   4553   errors)
   4554 
   4555 (defun flycheck-remove-error-file-names (file-name errors)
   4556   "Remove matching FILE-NAME from ERRORS.
   4557 
   4558 Use as `:error-filter' for syntax checkers that output faulty
   4559 filenames.  Flycheck will later fill in the buffer file name.
   4560 
   4561 Return ERRORS."
   4562   (seq-do (lambda (err)
   4563             (when (and (flycheck-error-filename err)
   4564                        (string= (flycheck-error-filename err) file-name))
   4565               (setf (flycheck-error-filename err) nil)))
   4566           errors)
   4567   errors)
   4568 
   4569 (defun flycheck-increment-error-columns (errors &optional offset)
   4570   "Increment all columns of ERRORS by OFFSET (default: 1).
   4571 
   4572   Use this as `:error-filter' if a syntax checker outputs 0-based
   4573   columns."
   4574   (setq offset (or offset 1)) ;; Emacs bug #31715
   4575   (seq-do (lambda (err)
   4576             (when (flycheck-error-column err)
   4577               (cl-incf (flycheck-error-column err) offset))
   4578             (when (flycheck-error-end-column err)
   4579               (cl-incf (flycheck-error-end-column err) offset)))
   4580           errors)
   4581   errors)
   4582 
   4583 (defun flycheck-collapse-error-message-whitespace (errors)
   4584   "Collapse whitespace in all messages of ERRORS.
   4585 
   4586 Return ERRORS."
   4587   (dolist (err errors)
   4588     (when-let (message (flycheck-error-message err))
   4589       (setf (flycheck-error-message err)
   4590             (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r")))
   4591                                       " " message 'fixed-case 'literal))))
   4592   errors)
   4593 
   4594 (defun flycheck-dedent-error-messages (errors)
   4595   "Dedent all messages of ERRORS.
   4596 
   4597 For each error in ERRORS, determine the indentation offset from
   4598 the leading whitespace of the first line, and dedent all further
   4599 lines accordingly.
   4600 
   4601 Return ERRORS, with in-place modifications."
   4602   (dolist (err errors)
   4603     (when-let (message (flycheck-error-message err))
   4604       (with-temp-buffer
   4605         (insert message)
   4606         ;; Determine the indentation offset
   4607         (goto-char (point-min))
   4608         (back-to-indentation)
   4609         (let* ((indent-offset (- (point) (point-min))))
   4610           ;; Now iterate over all lines and dedent each according to
   4611           ;; `indent-offset'
   4612           (while (not (eobp))
   4613             (back-to-indentation)
   4614             ;; If the current line starts with sufficient whitespace, delete the
   4615             ;; indentation offset.  Otherwise keep the line intact, as we might
   4616             ;; loose valuable information
   4617             (when (>= (- (point) (line-beginning-position)) indent-offset)
   4618               (delete-char (- indent-offset)))
   4619             (forward-line 1)))
   4620         (delete-trailing-whitespace (point-min) (point-max))
   4621         (setf (flycheck-error-message err)
   4622               (buffer-substring-no-properties (point-min) (point-max))))))
   4623   errors)
   4624 
   4625 (defun flycheck-fold-include-levels (errors sentinel-message)
   4626   "Fold levels of ERRORS from included files.
   4627 
   4628 ERRORS is a list of `flycheck-error' objects.  SENTINEL-MESSAGE
   4629 is a regular expression matched against the error message to
   4630 determine whether the error denotes errors from an included
   4631 file.  Alternatively, it is a function that is given an error and
   4632 shall return non-nil, if the error denotes errors from an
   4633 included file."
   4634   (unless (or (stringp sentinel-message) (functionp sentinel-message))
   4635     (error "Sentinel must be string or function: %S" sentinel-message))
   4636   (let ((sentinel (if (functionp sentinel-message)
   4637                       sentinel-message
   4638                     (lambda (err)
   4639                       (string-match-p sentinel-message
   4640                                       (flycheck-error-message err)))))
   4641         (remaining-errors errors))
   4642     (while remaining-errors
   4643       (let* ((current-error (pop remaining-errors)))
   4644         (when (funcall sentinel current-error)
   4645           ;; We found an error denoting errors in the included file:
   4646           ;; 1. process all subsequent errors until faulty include file is found
   4647           ;; 2. process again all subsequent errors until an error has the
   4648           ;;    current file name again
   4649           ;; 3. find the most severe error level
   4650           (let ((current-filename (flycheck-error-filename current-error))
   4651                 (current-level nil)
   4652                 (faulty-include-filename nil)
   4653                 (filename nil)
   4654                 (done (null remaining-errors)))
   4655 
   4656             (while (not done)
   4657               (setq filename (flycheck-error-filename (car remaining-errors)))
   4658               (unless faulty-include-filename
   4659                 (unless (string= filename current-filename)
   4660                   (setq faulty-include-filename filename)))
   4661 
   4662               (let* ((error-in-include (pop remaining-errors))
   4663                      (in-include-level (flycheck-error-level error-in-include)))
   4664                 (unless (funcall sentinel error-in-include)
   4665                   ;; Ignore nested "included file" errors, we are only
   4666                   ;; interested in real errors because these define our level
   4667                   (when (or (not current-level)
   4668                             (> (flycheck-error-level-severity in-include-level)
   4669                                (flycheck-error-level-severity current-level)))
   4670                     (setq current-level in-include-level))))
   4671 
   4672               (setq done (or (null remaining-errors)
   4673                              (and faulty-include-filename
   4674                                   (string= filename current-filename)))))
   4675 
   4676             (setf (flycheck-error-level current-error) current-level
   4677                   (flycheck-error-message current-error)
   4678                   (format "In include %s" faulty-include-filename))))))
   4679     errors))
   4680 
   4681 (defun flycheck-dequalify-error-ids (errors)
   4682   "De-qualify error ids in ERRORS.
   4683 
   4684 Remove all qualifications from error ids in ERRORS, by stripping
   4685 all leading dotted components from error IDs.  For instance, if
   4686 the error ID is com.foo.E100, replace it with E100.
   4687 
   4688 This error filter is mainly useful to simplify error IDs obtained
   4689 from parsing Checkstyle XML, which frequently has very verbose
   4690 IDs, that include the name of the tool."
   4691   (seq-do (lambda (err)
   4692             (let ((id (flycheck-error-id err)))
   4693               (when id
   4694                 (setf (flycheck-error-id err)
   4695                       (replace-regexp-in-string
   4696                        (rx string-start
   4697                            (group
   4698                             (optional (zero-or-more not-newline) "."))
   4699                            (one-or-more (not (any ".")))
   4700                            string-end)
   4701                        "" id 'fixedcase 'literal 1)))))
   4702           errors)
   4703   errors)
   4704 
   4705 (defun flycheck-remove-error-ids (errors)
   4706   "Remove all error ids from ERRORS."
   4707   (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors)
   4708   errors)
   4709 
   4710 (defun flycheck-fill-empty-line-numbers (errors)
   4711   "Set ERRORS without lines to line 0.
   4712 
   4713 Use as `:error-filter' for syntax checkers that output errors
   4714 without line numbers.
   4715 
   4716 Return ERRORS."
   4717   (seq-do (lambda (err)
   4718             (unless (flycheck-error-line err)
   4719               (setf (flycheck-error-line err) 0)))
   4720           errors)
   4721   errors)
   4722 
   4723 
   4724 ;;; Error analysis
   4725 (defun flycheck-count-errors (errors)
   4726   "Count the number of ERRORS, grouped by level.
   4727 
   4728 Return an alist, where each ITEM is a cons cell whose `car' is an
   4729 error level, and whose `cdr' is the number of errors of that
   4730 level."
   4731   (let (counts-by-level)
   4732     (dolist (err errors)
   4733       (let* ((level (flycheck-error-level err))
   4734              (item (assq level counts-by-level)))
   4735         (if item
   4736             (cl-incf (cdr item))
   4737           (push (cons level 1) counts-by-level))))
   4738     counts-by-level))
   4739 
   4740 (defun flycheck-has-max-errors-p (errors level)
   4741   "Check if there is no error in ERRORS more severe than LEVEL."
   4742   (let ((severity (flycheck-error-level-severity level)))
   4743     (seq-every-p (lambda (e) (<= (flycheck-error-level-severity
   4744                                   (flycheck-error-level e))
   4745                                  severity))
   4746                  errors)))
   4747 
   4748 (defun flycheck-has-max-current-errors-p (level)
   4749   "Check if there is no current error more severe than LEVEL."
   4750   (flycheck-has-max-errors-p flycheck-current-errors level))
   4751 
   4752 (defun flycheck-has-errors-p (errors level)
   4753   "Determine if there are any ERRORS with LEVEL."
   4754   (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors))
   4755 
   4756 (defun flycheck-has-current-errors-p (&optional level)
   4757   "Determine if the current buffer has errors with LEVEL.
   4758 
   4759 If LEVEL is omitted if the current buffer has any errors at all."
   4760   (if level
   4761       (flycheck-has-errors-p flycheck-current-errors level)
   4762     (and flycheck-current-errors t)))
   4763 
   4764 
   4765 ;;; Error overlays in the current buffer
   4766 (defvar-local flycheck--last-overlay-index 0
   4767   "Last index given to a Flycheck overlay.
   4768 
   4769 These indices are used to preserve error order (Emacs doesn't
   4770 preserve overlay order when calling `overlays-at').")
   4771 
   4772 (defun flycheck--next-overlay-index ()
   4773   "Compute the index to assign to a new Flycheck overlay."
   4774   (cl-incf flycheck--last-overlay-index))
   4775 
   4776 (defun flycheck--highlighting-style (err)
   4777   "Determine the highlighting style to apply to ERR.
   4778 
   4779 Styles are documented in `flycheck-highlighting-style'; this
   4780 functions resolves `conditional' style specifications."
   4781   (let* ((style flycheck-highlighting-style)
   4782          (first-line (flycheck-error-line err))
   4783          (end-line (or (flycheck-error-end-line err) first-line))
   4784          (nlines (- end-line first-line)))
   4785     (while (eq (car-safe style) 'conditional)
   4786       (pcase-let ((`(,threshold ,s1 ,s2) (cdr style)))
   4787         (setq style (if (< nlines threshold) s1 s2))))
   4788     (pcase style
   4789       (`(delimiters ,before ,after)
   4790        (when (characterp before)
   4791          (setq before (flycheck--make-highlighting-delimiter before)))
   4792        (when (characterp after)
   4793          (setq after (flycheck--make-highlighting-delimiter after)))
   4794        (setq style `(delimiters ,before ,after))))
   4795     style))
   4796 
   4797 (defun flycheck--setup-highlighting (err overlay)
   4798   "Apply properties to OVERLAY to highlight ERR."
   4799   (let ((level (flycheck-error-level err)))
   4800     (unless flycheck-highlighting-mode
   4801       ;; Erase the highlighting from the overlay if requested by the user
   4802       (setf (overlay-get overlay 'face) nil))
   4803     (when flycheck-indication-mode
   4804       (setf (overlay-get overlay 'before-string)
   4805             (flycheck-error-level-make-indicator
   4806              level flycheck-indication-mode))
   4807       (setf (overlay-get overlay 'line-prefix)
   4808             (flycheck-error-level-make-indicator
   4809              level flycheck-indication-mode t)))
   4810     (pcase (flycheck--highlighting-style err)
   4811       ((or `nil (guard (null flycheck-highlighting-mode)))
   4812        ;; Erase the highlighting
   4813        (setf (overlay-get overlay 'face) nil))
   4814       (`level-face)
   4815       (`(delimiters ,before ,after)
   4816        ;; Replace the highlighting with delimiters
   4817        (let* ((fringe-face (flycheck-error-level-fringe-face level))
   4818               (delim-face `(flycheck-error-delimiter ,fringe-face)))
   4819          (setf (overlay-get overlay 'face) 'flycheck-delimited-error)
   4820          (setf (overlay-get overlay 'before-string)
   4821                (concat (propertize before 'face delim-face)
   4822                        (or (overlay-get overlay 'before-string) "")))
   4823          (setf (overlay-get overlay 'after-string)
   4824                (propertize after 'face delim-face))))
   4825       (other (error "Unsupported highlighting style: %S" other)))))
   4826 
   4827 (defun flycheck-add-overlay (err)
   4828   "Add overlay for ERR.
   4829 
   4830 Return the created overlay."
   4831   ;; We must have a proper error region for the sake of fringe indication,
   4832   ;; error display and error navigation, even if the highlighting is disabled.
   4833   ;; We erase the highlighting later on in this case
   4834   (pcase-let* ((`(,beg . ,end)
   4835                 (if (flycheck-relevant-error-other-file-p err)
   4836                     ;; Display overlays for other-file errors on the first line
   4837                     (cons (point-min)
   4838                           (save-excursion (goto-char (point-min))
   4839                                           (line-end-position)))
   4840                   (flycheck-error-region-for-mode
   4841                    err (or flycheck-highlighting-mode 'lines))))
   4842                (overlay (make-overlay beg end))
   4843                (level (flycheck-error-level err))
   4844                (category (flycheck-error-level-overlay-category level))
   4845                (index (flycheck--next-overlay-index)))
   4846     (unless (flycheck-error-level-p level)
   4847       (error "Undefined error level: %S" level))
   4848     (setf (overlay-get overlay 'flycheck-error-index) index)
   4849     (setf (overlay-get overlay 'flycheck-overlay) t)
   4850     (setf (overlay-get overlay 'flycheck-error) err)
   4851     (setf (overlay-get overlay 'category) category)
   4852     (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo)
   4853     (flycheck--setup-highlighting err overlay)
   4854     overlay))
   4855 
   4856 (defun flycheck-help-echo (_window object pos)
   4857   "Construct a tooltip message.
   4858 
   4859 Most of the actual work is done by calling
   4860 `flycheck-help-echo-function' with the appropriate list of
   4861 errors.  Arguments WINDOW, OBJECT and POS are as described in
   4862 info node `(elisp)Special properties', as this function is
   4863 intended to be used as the \\='help-echo property of flycheck error
   4864 overlays."
   4865   (when-let (buf (cond ((bufferp object) object)
   4866                        ((overlayp object) (overlay-buffer object))))
   4867     (with-current-buffer buf
   4868       (when-let* ((fn flycheck-help-echo-function)
   4869                   (errs (flycheck-overlay-errors-at pos)))
   4870         (propertize (funcall fn errs) 'help-echo-inhibit-substitution t)))))
   4871 
   4872 (defun flycheck-help-echo-all-error-messages (errs)
   4873   "Concatenate error messages and ids from ERRS."
   4874   (pcase (delq nil errs) ;; FIXME why would errors be nil here?
   4875     (`(,err) ;; A single error
   4876      (flycheck-error-format-message-and-id err))
   4877     (_ ;; Zero or multiple errors
   4878      (mapconcat
   4879       (lambda (err)
   4880         (flycheck-error-format-message-and-id err 'include-snippet))
   4881       errs "\n"))))
   4882 
   4883 (defun flycheck-filter-overlays (overlays)
   4884   "Get all Flycheck overlays from OVERLAYS, in original order."
   4885   ;; The order of errors returned from overlays is not stable, so we sort
   4886   ;; them again using the internal index to guarantee errors are always
   4887   ;; displayed in the same order.
   4888   (seq-sort
   4889    ;; We can't use `seq-sort-by' here; see above
   4890    (lambda (o1 o2) (< (overlay-get o1 'flycheck-error-index)
   4891                       (overlay-get o2 'flycheck-error-index)))
   4892    (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays)))
   4893 
   4894 (defun flycheck-overlays-at (pos)
   4895   "Get all Flycheck overlays at POS."
   4896   (flycheck-filter-overlays (overlays-at pos)))
   4897 
   4898 (defun flycheck-overlays-in (beg end)
   4899   "Get all Flycheck overlays between BEG and END."
   4900   (flycheck-filter-overlays (overlays-in beg end)))
   4901 
   4902 (defun flycheck-overlay-errors-at (pos)
   4903   "Return a list of all flycheck errors overlaid at POS."
   4904   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
   4905            (flycheck-overlays-at pos)))
   4906 
   4907 (defun flycheck-overlay-errors-in (beg end)
   4908   "Return a list of all flycheck errors overlaid between BEG and END."
   4909   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
   4910            (flycheck-overlays-in beg end)))
   4911 
   4912 (defvar-local flycheck-overlays-to-delete nil
   4913   "Overlays mark for deletion after all syntax checks completed.")
   4914 (put 'flycheck-overlays-to-delete 'permanent-local t)
   4915 
   4916 (defun flycheck-delete-all-overlays ()
   4917   "Remove all flycheck overlays in the current buffer."
   4918   (overlay-recenter (point-max))
   4919   (flycheck-delete-marked-overlays)
   4920   (setq flycheck--last-overlay-index 0)
   4921   (save-restriction
   4922     (widen)
   4923     (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max)))))
   4924 
   4925 (defun flycheck-mark-all-overlays-for-deletion ()
   4926   "Mark all current overlays for deletion."
   4927   (setq flycheck-overlays-to-delete
   4928         (append (flycheck-overlays-in (point-min) (point-max))
   4929                 flycheck-overlays-to-delete)))
   4930 
   4931 (defun flycheck-delete-marked-overlays ()
   4932   "Delete all overlays marked for deletion."
   4933   (overlay-recenter (point-max))
   4934   (seq-do #'delete-overlay flycheck-overlays-to-delete)
   4935   (setq flycheck-overlays-to-delete nil))
   4936 
   4937 
   4938 ;;; Error navigation in the current buffer
   4939 (defun flycheck-error-level-interesting-at-pos-p (pos)
   4940   "Check if error severity at POS passes `flycheck-error-level-interesting-p'."
   4941   (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error)))
   4942 
   4943 (defun flycheck-error-level-interesting-p (err)
   4944   "Check if ERR severity is >= `flycheck-navigation-minimum-level'.
   4945 
   4946 ERR is also interesting (the function returns true) if there are
   4947 no errors as or more severe than `flycheck-navigation-minimum-level'."
   4948   (when (flycheck-error-p err)
   4949     (if-let (min-level flycheck-navigation-minimum-level)
   4950         (or (<= (flycheck-error-level-severity min-level)
   4951                 (flycheck-error-level-severity (flycheck-error-level err)))
   4952             (not (flycheck-has-current-errors-p min-level)))
   4953       t)))
   4954 
   4955 (defun flycheck-next-error-pos (n &optional reset)
   4956   "Get the position of the N-th next error.
   4957 
   4958 With negative N, get the position of the (-N)-th previous error
   4959 instead.  With non-nil RESET, search from `point-min', otherwise
   4960 search from the current point.
   4961 
   4962 Return the position of the next or previous error, or nil if
   4963 there is none.  If N is zero, return `point', or `point-min' if
   4964 RESET is non-nil."
   4965   (let ((n (or n 1))
   4966         (pos (if reset (point-min) (point))))
   4967     (if (>= n 0)
   4968         ;; Search forwards
   4969         (while (and pos (> n 0))
   4970           (setq n (1- n))
   4971           (when (get-char-property pos 'flycheck-error)
   4972             ;; Move beyond from the current error if any
   4973             (setq pos (next-single-char-property-change pos 'flycheck-error)))
   4974           (while (not (or (= pos (point-max))
   4975                           (flycheck-error-level-interesting-at-pos-p pos)))
   4976             ;; Scan for the next error
   4977             (setq pos (next-single-char-property-change pos 'flycheck-error)))
   4978           (when (and (= pos (point-max))
   4979                      (not (flycheck-error-level-interesting-at-pos-p pos)))
   4980             ;; If we reached the end of the buffer, but no error, we didn't find
   4981             ;; any
   4982             (setq pos nil)))
   4983       ;; Search backwards
   4984       (while (and pos (< n 0))
   4985         (setq n (1+ n))
   4986         ;; Loop until we find an error.  We need to check the position *before*
   4987         ;; the current one, because `previous-single-char-property-change'
   4988         ;; always moves to the position *of* the change.
   4989         (while (not (or (= pos (point-min))
   4990                         (flycheck-error-level-interesting-at-pos-p (1- pos))))
   4991           (setq pos (previous-single-char-property-change pos 'flycheck-error)))
   4992         (when (and (= pos (point-min))
   4993                    (not (flycheck-error-level-interesting-at-pos-p pos)))
   4994           ;; We didn't find any error.
   4995           (setq pos nil))
   4996         (when pos
   4997           ;; We found an error, so move to its beginning
   4998           (setq pos (previous-single-char-property-change pos
   4999                                                           'flycheck-error)))))
   5000     pos))
   5001 
   5002 (defun flycheck-next-error-function (n reset)
   5003   "Visit the N-th error from the current point.
   5004 
   5005 N is the number of errors to advance by, where a negative N
   5006 advances backwards.  With non-nil RESET, advance from the
   5007 beginning of the buffer, otherwise advance from the current
   5008 position.
   5009 
   5010 Intended for use with `next-error-function'."
   5011   (if-let* ((pos (flycheck-next-error-pos n reset))
   5012             (err (get-char-property pos 'flycheck-error)))
   5013       (flycheck-jump-to-error err)
   5014     (user-error "No more Flycheck errors")))
   5015 
   5016 (defun flycheck-next-error (&optional n reset)
   5017   "Visit the N-th error from the current point.
   5018 
   5019 N is the number of errors to advance by, where a negative N
   5020 advances backwards.  With non-nil RESET, advance from the
   5021 beginning of the buffer, otherwise advance from the current
   5022 position."
   5023   (interactive "P")
   5024   (when (consp n)
   5025     ;; Universal prefix argument means reset
   5026     (setq reset t n nil))
   5027   (flycheck-next-error-function n reset)
   5028   (flycheck-display-error-at-point))
   5029 
   5030 (defun flycheck-previous-error (&optional n)
   5031   "Visit the N-th previous error.
   5032 
   5033 If given, N specifies the number of errors to move backwards by.
   5034 If N is negative, move forwards instead."
   5035   (interactive "P")
   5036   (flycheck-next-error (- (or n 1))))
   5037 
   5038 (defun flycheck-first-error (&optional n)
   5039   "Visit the N-th error from beginning of the buffer.
   5040 
   5041 If given, N specifies the number of errors to move forward from
   5042 the beginning of the buffer."
   5043   (interactive "P")
   5044   (flycheck-next-error n 'reset))
   5045 
   5046 
   5047 ;;; Listing errors in buffers
   5048 (defconst flycheck-error-list-buffer "*Flycheck errors*"
   5049   "The name of the buffer to show error lists.")
   5050 
   5051 (defmacro flycheck-error-list-with-buffer (&rest body)
   5052   "Evaluate BODY in flycheck-error-list-buffer, if it exists."
   5053   (declare (indent 0) (debug t))
   5054   `(when (get-buffer flycheck-error-list-buffer)
   5055      (with-current-buffer flycheck-error-list-buffer
   5056        ,@body)))
   5057 
   5058 (defvar flycheck-error-list-mode-map
   5059   (let ((map (make-sparse-keymap)))
   5060     (define-key map (kbd "f") #'flycheck-error-list-set-filter)
   5061     (define-key map (kbd "F") #'flycheck-error-list-reset-filter)
   5062     (define-key map (kbd "n") #'flycheck-error-list-next-error)
   5063     (define-key map (kbd "p") #'flycheck-error-list-previous-error)
   5064     (define-key map (kbd "g") #'flycheck-error-list-check-source)
   5065     (define-key map (kbd "e") #'flycheck-error-list-explain-error)
   5066     (define-key map (kbd "RET") #'flycheck-error-list-goto-error)
   5067     map)
   5068   "The keymap of `flycheck-error-list-mode'.")
   5069 
   5070 (defun flycheck-error-list-make-last-column (message checker)
   5071   "Compute contents of the last error list cell.
   5072 
   5073 MESSAGE and CHECKER are displayed in a single column to allow the
   5074 message to stretch arbitrarily far."
   5075   (let ((checker-name (propertize (symbol-name checker)
   5076                                   'face 'flycheck-error-list-checker-name))
   5077         (message (propertize message
   5078                              'face 'flycheck-error-list-error-message)))
   5079     (format "%s (%s)" message checker-name)))
   5080 
   5081 (defconst flycheck-error-list-format
   5082   `[("File" 6)
   5083     ("Line" 5 flycheck-error-list-entry-< :right-align t)
   5084     ("Col" 3 nil :right-align t)
   5085     ("Level" 8 flycheck-error-list-entry-level-<)
   5086     ("ID" 6 t)
   5087     (,(flycheck-error-list-make-last-column "Message" 'Checker) 0 t)]
   5088   "Table format for the error list.")
   5089 
   5090 (defconst flycheck-error-list-padding 1
   5091   "Padding used in error list.")
   5092 
   5093 (defconst flycheck--error-list-msg-offset
   5094   (seq-reduce
   5095    (lambda (offset fmt)
   5096      (pcase-let* ((`(,_ ,width ,_ . ,props) fmt)
   5097                   (padding (or (plist-get props :pad-right) 1)))
   5098        (+ offset width padding)))
   5099    (seq-subseq flycheck-error-list-format 0 -1)
   5100    flycheck-error-list-padding)
   5101   "Amount of space to use in `flycheck-flush-multiline-message'.")
   5102 
   5103 (define-derived-mode flycheck-error-list-mode tabulated-list-mode
   5104   "Flycheck errors"
   5105   "Major mode for listing Flycheck errors.
   5106 
   5107 \\{flycheck-error-list-mode-map}"
   5108   (setq tabulated-list-format flycheck-error-list-format
   5109         ;; Sort by location initially
   5110         tabulated-list-sort-key (cons "Line" nil)
   5111         tabulated-list-padding flycheck-error-list-padding
   5112         tabulated-list-entries #'flycheck-error-list-entries
   5113         ;; `revert-buffer' updates the mode line for us, so all we need to do is
   5114         ;; set the corresponding mode line construct.
   5115         mode-line-buffer-identification flycheck-error-list-mode-line)
   5116   ;; See https://github.com/flycheck/flycheck/issues/1101
   5117   (setq-local truncate-string-ellipsis "…")
   5118   (tabulated-list-init-header))
   5119 
   5120 (defvar-local flycheck-error-list-source-buffer nil
   5121   "The current source buffer of the error list.")
   5122 ;; Needs to permanently local to preserve the source buffer across buffer
   5123 ;; reversions
   5124 (put 'flycheck-error-list-source-buffer 'permanent-local t)
   5125 
   5126 (defun flycheck-error-list-set-source (buffer)
   5127   "Set BUFFER as the source buffer of the error list."
   5128   (flycheck-error-list-with-buffer
   5129     (setq flycheck-error-list-source-buffer buffer)
   5130     (flycheck-error-list-refresh)))
   5131 
   5132 (defun flycheck-error-list-update-source ()
   5133   "Make the error list display errors from the current buffer.
   5134 
   5135 The update is skipped if the current buffer is the error list or
   5136 if the error list is already pointing to the current buffer."
   5137   (unless (memq (current-buffer)
   5138                 (list (get-buffer flycheck-error-list-buffer)
   5139                       (flycheck-error-list-with-buffer
   5140                         flycheck-error-list-source-buffer)))
   5141     (flycheck-error-list-set-source (current-buffer))))
   5142 
   5143 (defun flycheck-error-list-check-source ()
   5144   "Trigger a syntax check in the source buffer of the error list."
   5145   (interactive)
   5146   (let ((buffer (get-buffer flycheck-error-list-source-buffer)))
   5147     (when (buffer-live-p buffer)
   5148       (with-current-buffer buffer
   5149         (flycheck-buffer)))))
   5150 
   5151 (define-button-type 'flycheck-error-list
   5152   'action #'flycheck-error-list-goto-error
   5153   'help-echo "mouse-1, RET: goto error"
   5154   'face nil)
   5155 
   5156 (define-button-type 'flycheck-error-list-explain-error
   5157   'action #'flycheck-error-list-explain-error
   5158   'help-echo "mouse-1, RET: explain error")
   5159 
   5160 (defsubst flycheck-error-list-make-cell (text &optional face help-echo type)
   5161   "Make an error list cell with TEXT and FACE.
   5162 
   5163 If FACE is nil don't set a FACE on TEXT.  If TEXT already has
   5164 face properties, do not specify a FACE.  Note though, that if
   5165 TEXT gets truncated it will not inherit any previous face
   5166 properties.  If you expect TEXT to be truncated in the error
   5167 list, do specify a FACE explicitly!
   5168 
   5169 If HELP-ECHO is non-nil, set a help-echo property on TEXT, with
   5170 value HELP-ECHO.  This is convenient if you expect TEXT to be
   5171 truncated.
   5172 
   5173 The cell will have the type TYPE unless TYPE is nil, and the
   5174 default type `flycheck-error-list' will be used instead."
   5175   (append (list text 'type (if type type
   5176                              'flycheck-error-list))
   5177           (and face (list 'face face))
   5178           (and help-echo (list 'help-echo help-echo))))
   5179 
   5180 (defsubst flycheck-error-list-make-number-cell (number face)
   5181   "Make a table cell for a NUMBER with FACE.
   5182 
   5183 Convert NUMBER to string, fontify it with FACE and return the
   5184 string with attached text properties."
   5185   (flycheck-error-list-make-cell
   5186    (if (numberp number) (number-to-string number) "")
   5187    face))
   5188 
   5189 (defun flycheck-error-list-make-entry (error)
   5190   "Make a table cell for the given ERROR.
   5191 
   5192 Return a list with the contents of the table cell."
   5193   (let* ((level (flycheck-error-level error))
   5194          (level-face (flycheck-error-level-error-list-face level))
   5195          (filename (flycheck-error-filename error))
   5196          (line (flycheck-error-line error))
   5197          (column (flycheck-error-column error))
   5198          (message (or (flycheck-error-message error)
   5199                       (format "Unknown %S" level)))
   5200          (flushed-msg (flycheck-flush-multiline-message message))
   5201          (id (flycheck-error-id error))
   5202          (id-str (if id (format "%s" id) ""))
   5203          (checker (flycheck-error-checker error))
   5204          (msg-and-checker
   5205           (flycheck-error-list-make-last-column flushed-msg checker))
   5206          (explainer (flycheck-checker-get checker 'error-explainer)))
   5207     (list error
   5208           (vector (flycheck-error-list-make-cell
   5209                    (if filename
   5210                        (file-name-nondirectory filename)
   5211                      "")
   5212                    'flycheck-error-list-filename)
   5213                   (flycheck-error-list-make-number-cell
   5214                    line 'flycheck-error-list-line-number)
   5215                   (flycheck-error-list-make-number-cell
   5216                    column 'flycheck-error-list-column-number)
   5217                   (flycheck-error-list-make-cell
   5218                    (symbol-name (flycheck-error-level error)) level-face)
   5219                   ;; Error ID use a different face when an error-explainer is
   5220                   ;; present
   5221                   (flycheck-error-list-make-cell
   5222                    id-str (if explainer 'flycheck-error-list-id-with-explainer
   5223                             'flycheck-error-list-id)
   5224                    id-str 'flycheck-error-list-explain-error)
   5225                   (flycheck-error-list-make-cell
   5226                    msg-and-checker nil msg-and-checker)))))
   5227 
   5228 (defun flycheck-flush-multiline-message (msg)
   5229   "Prepare error message MSG for display in the error list.
   5230 
   5231 Prepend all lines of MSG except the first with enough space to
   5232 ensure that they line up properly once the message is displayed."
   5233   (let* ((spc-spec `(space . (:width ,flycheck--error-list-msg-offset)))
   5234          (spc (propertize " " 'display spc-spec))
   5235          (rep (concat "\\1" spc "\\2")))
   5236     (replace-regexp-in-string "\\([\r\n]+\\)\\(.\\)" rep msg)))
   5237 
   5238 (defun flycheck-error-list-current-errors ()
   5239   "Read the list of errors in `flycheck-error-list-source-buffer'."
   5240   (when (buffer-live-p flycheck-error-list-source-buffer)
   5241     (buffer-local-value 'flycheck-current-errors
   5242                         flycheck-error-list-source-buffer)))
   5243 
   5244 (defun flycheck-error-list-entries ()
   5245   "Create the entries for the error list."
   5246   (when-let* ((errors (flycheck-error-list-current-errors))
   5247               (filtered (flycheck-error-list-apply-filter errors)))
   5248     (seq-map #'flycheck-error-list-make-entry filtered)))
   5249 
   5250 (defun flycheck-error-list-entry-< (entry1 entry2)
   5251   "Determine whether ENTRY1 is before ENTRY2 by location.
   5252 
   5253 See `flycheck-error-<'."
   5254   (flycheck-error-< (car entry1) (car entry2)))
   5255 
   5256 (defun flycheck-error-list-entry-level-< (entry1 entry2)
   5257   "Determine whether ENTRY1 is before ENTRY2 by level.
   5258 
   5259 See `flycheck-error-level-<'."
   5260   (not (flycheck-error-level-< (car entry1) (car entry2))))
   5261 
   5262 (defvar flycheck-error-list-mode-line-map
   5263   (let ((map (make-sparse-keymap)))
   5264     (define-key map [mode-line mouse-1]
   5265       #'flycheck-error-list-mouse-switch-to-source)
   5266     map)
   5267   "Keymap for error list mode line.")
   5268 
   5269 (defun flycheck-error-list-propertized-source-name ()
   5270   "Get the name of the current source buffer for the mode line.
   5271 
   5272 Propertize the name of the current source buffer for use in the
   5273 mode line indication of `flycheck-error-list-mode'."
   5274   (let ((name (replace-regexp-in-string
   5275                (rx "%") "%%"
   5276                (buffer-name flycheck-error-list-source-buffer)
   5277                'fixed-case 'literal)))
   5278     (propertize name 'face 'mode-line-buffer-id
   5279                 'mouse-face 'mode-line-highlight
   5280                 'help-echo "mouse-1: switch to source"
   5281                 'local-map flycheck-error-list-mode-line-map)))
   5282 
   5283 (defun flycheck-error-list-mouse-switch-to-source (event)
   5284   "Switch to the error list source buffer of the EVENT window."
   5285   (interactive "e")
   5286   (save-selected-window
   5287     (when (eventp event)
   5288       (select-window (posn-window (event-start event))))
   5289     (when (buffer-live-p flycheck-error-list-source-buffer)
   5290       (switch-to-buffer flycheck-error-list-source-buffer))))
   5291 
   5292 (defun flycheck-get-error-list-window-list (&optional all-frames)
   5293   "Get all windows displaying the error list.
   5294 
   5295 ALL-FRAMES specifies the frames to consider, as in
   5296 `get-buffer-window-list'."
   5297   (when-let (buf (get-buffer flycheck-error-list-buffer))
   5298     (get-buffer-window-list buf nil all-frames)))
   5299 
   5300 (defun flycheck-get-error-list-window (&optional all-frames)
   5301   "Get a window displaying the error list, or nil if none.
   5302 
   5303 ALL-FRAMES specifies the frames to consider, as in
   5304 `get-buffer-window'."
   5305   (when-let (buf (get-buffer flycheck-error-list-buffer))
   5306     (get-buffer-window buf all-frames)))
   5307 
   5308 (defun flycheck-error-list-recenter-at (pos)
   5309   "Recenter the error list at POS."
   5310   (dolist (window (flycheck-get-error-list-window-list t))
   5311     (with-selected-window window
   5312       (goto-char pos)
   5313       (let ((recenter-redisplay nil))
   5314         (recenter)))))
   5315 
   5316 (defun flycheck-error-list-refresh ()
   5317   "Refresh the current error list.
   5318 
   5319 Add all errors currently reported for the current
   5320 `flycheck-error-list-source-buffer', and recenter the error
   5321 list."
   5322   ;; We only refresh the error list, when it is visible in a window, and we
   5323   ;; select this window while reverting, because Tabulated List mode attempts to
   5324   ;; recenter the error at the old location, so it must have the proper window
   5325   ;; selected.
   5326   (when-let (window (flycheck-get-error-list-window t))
   5327     (with-selected-window window
   5328       (revert-buffer))
   5329     (run-hooks 'flycheck-error-list-after-refresh-hook)
   5330     (let ((preserve-pos (eq (current-buffer)
   5331                             (get-buffer flycheck-error-list-buffer))))
   5332       ;; If the error list is the current buffer, don't recenter when
   5333       ;; highlighting
   5334       (flycheck-error-list-highlight-errors preserve-pos))))
   5335 
   5336 (defun flycheck-error-list-mode-line-filter-indicator ()
   5337   "Create a string representing the current error list filter."
   5338   (if flycheck-error-list-minimum-level
   5339       (format " [>= %s]" flycheck-error-list-minimum-level)
   5340     ""))
   5341 
   5342 (defun flycheck-error-list-set-filter (level)
   5343   "Restrict the error list to errors at level LEVEL or higher.
   5344 
   5345 LEVEL is either an error level symbol, or nil, to remove the filter."
   5346   (interactive
   5347    (list (flycheck-read-error-level
   5348           "Minimum error level (errors at lower levels will be hidden): ")))
   5349   (when (and level (not (flycheck-error-level-p level)))
   5350     (user-error "Invalid level: %s" level))
   5351   (flycheck-error-list-with-buffer
   5352     (setq-local flycheck-error-list-minimum-level level)
   5353     (force-mode-line-update)
   5354     (flycheck-error-list-refresh)
   5355     (flycheck-error-list-recenter-at (point-min))))
   5356 
   5357 (defun flycheck-error-list-reset-filter (&optional refresh)
   5358   "Remove local error filters and reset to the default filter.
   5359 
   5360 Interactively, or with non-nil REFRESH, refresh the error list."
   5361   (interactive '(t))
   5362   (flycheck-error-list-with-buffer
   5363     (kill-local-variable 'flycheck-error-list-minimum-level)
   5364     (when refresh
   5365       (flycheck-error-list-refresh)
   5366       (flycheck-error-list-recenter-at (point-min))
   5367       (force-mode-line-update))))
   5368 
   5369 (defun flycheck-error-list-apply-filter (errors)
   5370   "Filter ERRORS according to `flycheck-error-list-minimum-level'."
   5371   (if-let* ((min-level flycheck-error-list-minimum-level)
   5372             (min-severity (flycheck-error-level-severity min-level)))
   5373       (seq-filter (lambda (err) (>= (flycheck-error-level-severity
   5374                                      (flycheck-error-level err))
   5375                                     min-severity))
   5376                   errors)
   5377     errors))
   5378 
   5379 (defun flycheck-error-list-goto-error (&optional pos)
   5380   "Go to the location of the error at POS in the error list.
   5381 
   5382 POS defaults to `point'."
   5383   (interactive)
   5384   (when-let* ((error (tabulated-list-get-id pos)))
   5385     (flycheck-jump-to-error error)))
   5386 
   5387 (defun flycheck-jump-to-error (error)
   5388   "Go to the location of ERROR."
   5389   (let* ((error-copy (copy-flycheck-error error))
   5390          (filename (flycheck-error-filename error))
   5391          (other-file-error (flycheck-relevant-error-other-file-p error))
   5392          (buffer (if filename
   5393                      (find-file-noselect filename)
   5394                    (flycheck-error-buffer error))))
   5395     (when (buffer-live-p buffer)
   5396       (setf (flycheck-error-buffer error-copy) buffer)
   5397       (flycheck-jump-in-buffer buffer error-copy)
   5398       ;; When jumping to an error in another file, it may not have
   5399       ;; this error available for highlighting yet, so we trigger a check
   5400       ;; if necessary.
   5401       (when other-file-error
   5402         (with-current-buffer buffer
   5403           ;; `seq-contains-p' is only in seq >= 2.21
   5404           (unless (with-no-warnings
   5405                     (seq-contains flycheck-current-errors error-copy 'equal))
   5406             (when flycheck-mode
   5407               (flycheck-buffer))))))))
   5408 
   5409 (defun flycheck-jump-in-buffer (buffer error)
   5410   "In BUFFER, jump to ERROR."
   5411   ;; FIXME: we assume BUFFER and the buffer of ERROR are the same.  We don't
   5412   ;; need the first argument then.
   5413   (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer))
   5414       ;; When called from within the error list, keep the error list,
   5415       ;; otherwise replace the current buffer.
   5416       (pop-to-buffer buffer 'other-window)
   5417     (switch-to-buffer buffer))
   5418   (let ((pos (flycheck-error-pos error)))
   5419     (unless (eq (goto-char pos) (point))
   5420       ;; If widening gets in the way of moving to the right place, remove it
   5421       ;; and try again
   5422       (widen)
   5423       (goto-char pos)))
   5424   ;; Re-highlight the errors.  We have post-command-hook for that, but calls to
   5425   ;; `flycheck-jump-in-buffer' that come from other buffers (e.g. from the error
   5426   ;; list) won't trigger it.
   5427   (flycheck-error-list-highlight-errors 'preserve-pos))
   5428 
   5429 (defun flycheck-error-list-explain-error (&optional pos)
   5430   "Explain the error at POS in the error list.
   5431 
   5432 POS defaults to `point'."
   5433   (interactive)
   5434   (when-let* ((error (tabulated-list-get-id pos))
   5435               (explainer (flycheck-checker-get (flycheck-error-checker error)
   5436                                                'error-explainer)))
   5437     (flycheck-error-with-buffer error
   5438       (when-let (explanation (funcall explainer error))
   5439         (flycheck-display-error-explanation explanation)))))
   5440 
   5441 (defun flycheck-error-list-next-error-pos (pos &optional n)
   5442   "Starting from POS get the N'th next error in the error list.
   5443 
   5444 N defaults to 1.  If N is negative, search for the previous error
   5445 instead.
   5446 
   5447 Get the beginning position of the N'th next error from POS, or
   5448 nil, if there is no next error."
   5449   (let ((n (or n 1)))
   5450     (if (>= n 0)
   5451         ;; Search forward
   5452         (while (and pos (/= n 0))
   5453           (setq n (1- n))
   5454           (setq pos (next-single-property-change pos 'tabulated-list-id)))
   5455       ;; Search backwards
   5456       (while (/= n 0)
   5457         (setq n (1+ n))
   5458         ;; We explicitly give the limit here to explicitly have the minimum
   5459         ;; point returned, to be able to move to the first error (which starts
   5460         ;; at `point-min')
   5461         (setq pos (previous-single-property-change pos 'tabulated-list-id
   5462                                                    nil (point-min)))))
   5463     pos))
   5464 
   5465 (defun flycheck-error-list-previous-error (n)
   5466   "Go to the N'th previous error in the error list."
   5467   (interactive "P")
   5468   (flycheck-error-list-next-error (- (or n 1))))
   5469 
   5470 (defun flycheck-error-list-next-error (n)
   5471   "Go to the N'th next error in the error list."
   5472   (interactive "P")
   5473   (let ((pos (flycheck-error-list-next-error-pos (point) n)))
   5474     (when (and pos (/= pos (point)))
   5475       (goto-char pos)
   5476       (save-selected-window
   5477         ;; Keep the error list selected, so that the user can navigate errors by
   5478         ;; repeatedly pressing n/p, without having to re-select the error list
   5479         ;; window.
   5480         (flycheck-error-list-goto-error)))))
   5481 
   5482 (defvar-local flycheck-error-list-highlight-overlays nil
   5483   "Error highlight overlays in the error list buffer.")
   5484 (put 'flycheck-error-list-highlight-overlays 'permanent-local t)
   5485 
   5486 (defun flycheck-error-list-highlight-errors (&optional preserve-pos)
   5487   "Highlight errors in the error list.
   5488 
   5489 Highlight all errors in the error list that are at point in the
   5490 source buffer, and on the same line as point.  Then recenter the
   5491 error list to the highlighted error, unless PRESERVE-POS is
   5492 non-nil."
   5493   (when (get-buffer flycheck-error-list-buffer)
   5494     (with-current-buffer flycheck-error-list-buffer
   5495       (let ((current-errors
   5496              (when (buffer-live-p flycheck-error-list-source-buffer)
   5497                (with-current-buffer flycheck-error-list-source-buffer
   5498                  (flycheck-overlay-errors-in (line-beginning-position)
   5499                                              (line-end-position))))))
   5500         (let ((old-overlays flycheck-error-list-highlight-overlays)
   5501               (min-point (point-max))
   5502               (max-point (point-min)))
   5503           ;; Display the new overlays first, to avoid re-display flickering
   5504           (setq flycheck-error-list-highlight-overlays nil)
   5505           (when current-errors
   5506             (let ((next-error-pos (point-min)))
   5507               (while next-error-pos
   5508                 (let* ((beg next-error-pos)
   5509                        (end (flycheck-error-list-next-error-pos beg))
   5510                        (err (tabulated-list-get-id beg)))
   5511                   (when (member err current-errors)
   5512                     (setq min-point (min min-point beg)
   5513                           max-point (max max-point beg))
   5514                     (let ((ov (make-overlay beg
   5515                                             ;; Extend overlay to the beginning
   5516                                             ;; of the next line, to highlight
   5517                                             ;; the whole line
   5518                                             (or end (point-max)))))
   5519                       (push ov flycheck-error-list-highlight-overlays)
   5520                       (setf (overlay-get ov 'flycheck-error-highlight-overlay)
   5521                             t)
   5522                       (setf (overlay-get ov 'face)
   5523                             'flycheck-error-list-highlight)))
   5524                   (setq next-error-pos end)))))
   5525           ;; Delete the old overlays
   5526           (seq-do #'delete-overlay old-overlays)
   5527           (when (and (not preserve-pos) current-errors)
   5528             ;; Move point to the middle error
   5529             (goto-char (+ min-point (/ (- max-point min-point) 2)))
   5530             (beginning-of-line)
   5531             ;; And recenter the error list at this position
   5532             (flycheck-error-list-recenter-at (point))))))))
   5533 
   5534 (defun flycheck-list-errors ()
   5535   "Show the error list for the current buffer."
   5536   (interactive)
   5537   (unless flycheck-mode
   5538     (user-error "Flycheck mode not enabled"))
   5539   ;; Create and initialize the error list
   5540   (unless (get-buffer flycheck-error-list-buffer)
   5541     (with-current-buffer (get-buffer-create flycheck-error-list-buffer)
   5542       (flycheck-error-list-mode)))
   5543   ;; Reset the error filter
   5544   (flycheck-error-list-reset-filter)
   5545   (let ((source (current-buffer)))
   5546     ;; Show the error list in a side window.  Under some configurations of
   5547     ;; `display-buffer', this may select `flycheck-error-list-buffer' (see URL
   5548     ;; `https://github.com/flycheck/flycheck/issues/1776').
   5549     (display-buffer flycheck-error-list-buffer)
   5550     ;; Adjust the source, causing a refresh
   5551     (flycheck-error-list-set-source source)))
   5552 
   5553 (defalias 'list-flycheck-errors 'flycheck-list-errors)
   5554 
   5555 
   5556 ;;; Displaying errors in the current buffer
   5557 (defun flycheck-display-errors (errors)
   5558   "Display ERRORS using `flycheck-display-errors-function'."
   5559   (when flycheck-display-errors-function
   5560     (funcall flycheck-display-errors-function errors)))
   5561 
   5562 (defun flycheck-clear-displayed-errors ()
   5563   "Clear errors using `flycheck-clear-displayed-errors-function'."
   5564   (when flycheck-clear-displayed-errors-function
   5565     (funcall flycheck-clear-displayed-errors-function)))
   5566 
   5567 (defvar-local flycheck-display-error-at-point-timer nil
   5568   "Timer to automatically show errors.")
   5569 
   5570 (defun flycheck-cancel-error-display-error-at-point-timer ()
   5571   "Cancel the error display timer for the current buffer."
   5572   (when flycheck-display-error-at-point-timer
   5573     (cancel-timer flycheck-display-error-at-point-timer)
   5574     (setq flycheck-display-error-at-point-timer nil)))
   5575 
   5576 (defun flycheck-display-error-at-point ()
   5577   "Display all the error messages at point.
   5578 
   5579 If there are no errors, clears the error messages at point."
   5580   (interactive)
   5581   ;; This function runs from a timer, so we must take care to not ignore any
   5582   ;; errors
   5583   (with-demoted-errors "Flycheck error display error: %s"
   5584     (flycheck-cancel-error-display-error-at-point-timer)
   5585     (when flycheck-mode
   5586       (let ((errors (flycheck-overlay-errors-at (point))))
   5587         (if errors
   5588             (flycheck-display-errors errors)
   5589           (flycheck-clear-displayed-errors))))))
   5590 
   5591 (defun flycheck-display-error-at-point-soon ()
   5592   "Display error messages at point, with a delay."
   5593   (flycheck-cancel-error-display-error-at-point-timer)
   5594   (setq flycheck-display-error-at-point-timer
   5595         (run-at-time flycheck-display-errors-delay nil
   5596                      'flycheck-display-error-at-point)))
   5597 
   5598 
   5599 ;;; Functions to display errors
   5600 (defconst flycheck-error-message-buffer "*Flycheck error messages*"
   5601   "The name of the buffer to show long error messages in.")
   5602 
   5603 (defun flycheck-error-message-buffer ()
   5604   "Get the buffer object to show long error messages in.
   5605 
   5606 Get the buffer named by variable `flycheck-error-message-buffer',
   5607 or nil if the buffer does not exist."
   5608   (get-buffer flycheck-error-message-buffer))
   5609 
   5610 (defun flycheck-may-use-echo-area-p ()
   5611   "Determine whether the echo area may be used.
   5612 
   5613 The echo area may be used if the cursor is not in the echo area,
   5614 and if the echo area is not occupied by minibuffer input."
   5615   (not (or cursor-in-echo-area (active-minibuffer-window))))
   5616 
   5617 (define-derived-mode flycheck-error-message-mode text-mode
   5618   "Flycheck error messages"
   5619   "Major mode for extended error messages.")
   5620 
   5621 (defvar flycheck--last-displayed-message nil
   5622   "Reference to the last displayed message so it can be cleared.
   5623 
   5624 This value is the return value from `display-message-or-buffer',
   5625 thus it can be a string or a window.
   5626 
   5627 See `flycheck-clear-displayed-error-messages'.")
   5628 
   5629 (defun flycheck-display-error-messages (errors)
   5630   "Display the messages of ERRORS.
   5631 
   5632 Concatenate all non-nil messages of ERRORS as with
   5633 `flycheck-help-echo-all-error-messages', and display them with
   5634 `display-message-or-buffer', which shows the messages either in
   5635 the echo area or in a separate buffer, depending on the number of
   5636 lines.  See Info node `(elisp)Displaying Messages' for more
   5637 information.
   5638 
   5639 In the latter case, show messages in the buffer denoted by
   5640 variable `flycheck-error-message-buffer'."
   5641   (when (and errors (flycheck-may-use-echo-area-p))
   5642     (let* ((message (flycheck-help-echo-all-error-messages errors))
   5643            (retval (display-message-or-buffer
   5644                     message flycheck-error-message-buffer 'not-this-window)))
   5645       ;; We cannot rely on `display-message-or-buffer' returning the right
   5646       ;; window. See URL `https://github.com/flycheck/flycheck/issues/1643'.
   5647       (when-let (buf (get-buffer flycheck-error-message-buffer))
   5648         (with-current-buffer buf
   5649           (unless (derived-mode-p 'flycheck-error-message-mode)
   5650             (flycheck-error-message-mode))))
   5651       (setq flycheck--last-displayed-message retval)
   5652       retval)))
   5653 
   5654 (defun flycheck-display-error-messages-unless-error-list (errors)
   5655   "Show messages of ERRORS unless the error list is visible.
   5656 
   5657 Like `flycheck-display-error-messages', but only if the error
   5658 list (see `flycheck-list-errors') is not visible in any window in
   5659 the current frame."
   5660   (unless (flycheck-get-error-list-window 'current-frame)
   5661     (flycheck-display-error-messages errors)))
   5662 
   5663 (defun flycheck-hide-error-buffer ()
   5664   "Hide the Flycheck error buffer if necessary.
   5665 
   5666 Hide the error buffer if there is no error under point."
   5667   (when-let* ((buffer (flycheck-error-message-buffer))
   5668               (window (get-buffer-window buffer)))
   5669     (unless (flycheck-overlays-at (point))
   5670       ;; save-selected-window prevents `quit-window' from changing the current
   5671       ;; buffer (see https://github.com/flycheck/flycheck/issues/648).
   5672       (save-selected-window
   5673         (quit-window nil window)))))
   5674 
   5675 (defun flycheck-clear-displayed-error-messages ()
   5676   "Clear error messages displayed by `flycheck-display-error-messages'."
   5677   (when flycheck--last-displayed-message
   5678     (if (and (stringp flycheck--last-displayed-message)
   5679              (equal (current-message) flycheck--last-displayed-message))
   5680         (message nil)
   5681       (flycheck-hide-error-buffer))))
   5682 
   5683 
   5684 ;;; Working with errors
   5685 (defun flycheck-copy-errors-as-kill (pos &optional formatter)
   5686   "Copy each error at POS into kill ring, using FORMATTER.
   5687 
   5688 FORMATTER is a function to turn an error into a string,
   5689 defaulting to `flycheck-error-message'.
   5690 
   5691 Interactively, use `flycheck-error-format-message-and-id' as
   5692 FORMATTER with universal prefix arg, and `flycheck-error-id' with
   5693 normal prefix arg, i.e. copy the message and the ID with
   5694 universal prefix arg, and only the id with normal prefix arg."
   5695   (interactive (list (point)
   5696                      (pcase current-prefix-arg
   5697                        ((pred not) #'flycheck-error-message)
   5698                        ((pred consp) #'flycheck-error-format-message-and-id)
   5699                        (_ #'flycheck-error-id))))
   5700   (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message)
   5701                                      (flycheck-overlay-errors-at pos)))))
   5702     (when messages
   5703       (seq-do #'kill-new (reverse messages))
   5704       (message (string-join messages "\n")))))
   5705 
   5706 (defun flycheck-explain-error-at-point ()
   5707   "Display an explanation for the first explainable error at point.
   5708 
   5709 The first explainable error at point is the first error at point
   5710 with a non-nil `:error-explainer' function defined in its
   5711 checker.  The `:error-explainer' function is then called with
   5712 this error to produce the explanation to display."
   5713   (interactive)
   5714   (when-let* ((first-error
   5715                ;; Get the first error at point that has an `error-explainer'.
   5716                (seq-find (lambda (error)
   5717                            (flycheck-checker-get
   5718                             (flycheck-error-checker error) 'error-explainer))
   5719                          (flycheck-overlay-errors-at (point))))
   5720               (explainer
   5721                (flycheck-checker-get (flycheck-error-checker first-error)
   5722                                      'error-explainer))
   5723               (explanation (funcall explainer first-error)))
   5724     (flycheck-display-error-explanation explanation)))
   5725 
   5726 (defconst flycheck-explain-error-buffer "*Flycheck error explanation*"
   5727   "The name of the buffer to show error explanations.")
   5728 
   5729 (define-derived-mode flycheck-explain-error-mode help-mode
   5730   "Error explanation"
   5731   "Major mode for displaying error explanations."
   5732   (setq buffer-read-only t))
   5733 
   5734 (defun flycheck-display-error-explanation (explanation)
   5735   "Display the EXPLANATION for an error."
   5736   (pcase explanation
   5737     (`nil)
   5738     (`(url . ,url) (browse-url url))
   5739     (_ (let ((inhibit-read-only t)
   5740              (standard-output (temp-buffer-window-setup
   5741                                flycheck-explain-error-buffer)))
   5742          (with-current-buffer standard-output
   5743            (flycheck-explain-error-mode))
   5744          (cond
   5745           ((functionp explanation) (funcall explanation))
   5746           ((stringp explanation) (princ explanation))
   5747           (t (error "Unsupported error explanation: %S" explanation)))
   5748          (display-message-or-buffer standard-output nil 'not-this-window)))))
   5749 
   5750 
   5751 ;;; Syntax checkers using external commands
   5752 (defun flycheck-command-argument-p (arg)
   5753   "Check whether ARG is a valid command argument."
   5754   (pcase arg
   5755     ((pred stringp) t)
   5756     ((or `source `source-inplace `source-original) t)
   5757     (`(,(or `source `source-inplace) ,suffix)
   5758      (stringp suffix))
   5759     ((or `temporary-directory `temporary-file-name) t)
   5760     (`null-device t)
   5761     (`(config-file ,option-name ,config-file-var)
   5762      (and (stringp option-name)
   5763           (symbolp config-file-var)))
   5764     (`(config-file ,option-name ,config-file-var ,prepender)
   5765      (and (stringp option-name)
   5766           (symbolp config-file-var)
   5767           (symbolp prepender)))
   5768     (`(,(or `option `option-list) ,option-name ,option-var)
   5769      (and (stringp option-name)
   5770           (symbolp option-var)))
   5771     (`(,(or `option `option-list) ,option-name ,option-var ,prepender)
   5772      (and (stringp option-name)
   5773           (symbolp option-var)
   5774           (symbolp prepender)))
   5775     (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter)
   5776      (and (stringp option-name)
   5777           (symbolp option-var)
   5778           (symbolp prepender)
   5779           (symbolp filter)))
   5780     (`(option-flag ,option-name ,option-var)
   5781      (and (stringp option-name)
   5782           (symbolp option-var)))
   5783     (`(eval ,_) t)
   5784     (_ nil)))
   5785 
   5786 (defun flycheck-compute-working-directory (checker)
   5787   "Get the default working directory for CHECKER.
   5788 
   5789 Compute the value of `default-directory' for the invocation of
   5790 the syntax checker command, by calling the function in the
   5791 `working-directory' property of CHECKER, with CHECKER as sole
   5792 argument, and returning its value.  Signal an error if the
   5793 function returns a non-existing working directory.
   5794 
   5795 If the property is undefined or if the function returns nil
   5796 return the `default-directory' of the current buffer."
   5797   (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory))
   5798          (directory (or (and def-directory-fn
   5799                              (funcall def-directory-fn checker))
   5800                         ;; Default to the `default-directory' of the current
   5801                         ;; buffer
   5802                         default-directory)))
   5803     (unless (file-exists-p directory)
   5804       (error ":working-directory %s of syntax checker %S does not exist"
   5805              directory checker))
   5806     directory))
   5807 
   5808 ;;;###autoload
   5809 (defun flycheck-define-command-checker (symbol docstring &rest properties)
   5810   "Define SYMBOL as syntax checker to run a command.
   5811 
   5812 Define SYMBOL as generic syntax checker via
   5813 `flycheck-define-generic-checker', which uses an external command
   5814 to check the buffer.  SYMBOL and DOCSTRING are the same as for
   5815 `flycheck-define-generic-checker'.
   5816 
   5817 In addition to the properties understood by
   5818 `flycheck-define-generic-checker', the following PROPERTIES
   5819 constitute a command syntax checker.  Unless otherwise noted, all
   5820 properties are mandatory.  Note that the default `:error-filter'
   5821 of command checkers is `flycheck-sanitize-errors'.
   5822 
   5823 `:command COMMAND'
   5824      The command to run for syntax checking.
   5825 
   5826      COMMAND is a list of the form `(EXECUTABLE [ARG ...])'.
   5827 
   5828      EXECUTABLE is a string with the executable of this syntax
   5829      checker.  It can be overridden with the variable
   5830      `flycheck-SYMBOL-executable'.  Note that this variable is
   5831      NOT implicitly defined by this function.  Use
   5832      `flycheck-def-executable-var' to define this variable.
   5833 
   5834      Each ARG is an argument to the executable, either as string,
   5835      or as special symbol or form for
   5836      `flycheck-substitute-argument', which see.
   5837 
   5838 `:error-patterns PATTERNS'
   5839      A list of patterns to parse the output of the `:command'.
   5840 
   5841      Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where
   5842      LEVEL is a Flycheck error level (see
   5843      `flycheck-define-error-level'), followed by one or more RX
   5844      `SEXP's which parse an error of that level and extract line,
   5845      column, file name and the message.
   5846 
   5847      See `rx' for general information about RX, and
   5848      `flycheck-rx-to-string' for some special RX forms provided
   5849      by Flycheck.
   5850 
   5851      All patterns are applied in the order of declaration to the
   5852      whole output of the syntax checker.  Output already matched
   5853      by a pattern will not be matched by subsequent patterns.  In
   5854      other words, the first pattern wins.
   5855 
   5856      This property is optional.  If omitted, however, an
   5857      `:error-parser' is mandatory.
   5858 
   5859 `:error-parser FUNCTION'
   5860      A function to parse errors with.
   5861 
   5862      The function shall accept three arguments OUTPUT CHECKER
   5863      BUFFER.  OUTPUT is the syntax checker output as string,
   5864      CHECKER the syntax checker that was used, and BUFFER a
   5865      buffer object representing the checked buffer.  The function
   5866      must return a list of `flycheck-error' objects parsed from
   5867      OUTPUT.
   5868 
   5869      This property is optional.  If omitted, it defaults to
   5870      `flycheck-parse-with-patterns'.  In this case,
   5871      `:error-patterns' is mandatory.
   5872 
   5873 `:standard-input t'
   5874      Whether to send the buffer contents on standard input.
   5875 
   5876      If this property is given and has a non-nil value, send the
   5877      contents of the buffer on standard input.
   5878 
   5879      Some checkers that support reading from standard input have
   5880      a separate flag to indicate the name of the file whose
   5881      contents are being passed on standard input (typically
   5882      `stdin-filename').  In that case, use the `(option)' form in
   5883      `:command' to pass the value of variable `buffer-file-name'
   5884      when the current buffer has a file name (that is,
   5885      use `option \"--stdin-file-name\" buffer-file-name').
   5886 
   5887      For buffers not backed by files, checkers that support input
   5888      on stdin typically report a file name like `-' or `<stdin>'.
   5889      Make sure your error parser or patterns expect these file
   5890      names (for example, use `(or \"<stdin>\" (file-name))') or
   5891      call `flycheck-remove-error-file-names' in a custom
   5892      `:error-filter'.
   5893 
   5894      Defaults to nil.
   5895 
   5896 Note that you may not give `:start', `:interrupt', and
   5897 `:print-doc' for a command checker.  You can give a custom
   5898 `:verify' function, though, whose results will be appended to the
   5899 default `:verify' function of command checkers."
   5900   (declare (indent 1)
   5901            (doc-string 2))
   5902   (dolist (prop '(:start :interrupt :print-doc))
   5903     (when (plist-get properties prop)
   5904       (error "%s not allowed in definition of command syntax checker %s"
   5905              prop symbol)))
   5906 
   5907   (unless (plist-get properties :error-filter)
   5908     ;; Default to `flycheck-sanitize-errors' as error filter
   5909     (setq properties (plist-put properties :error-filter
   5910                                 #'flycheck-sanitize-errors)))
   5911   (let ((verify-fn (plist-get properties :verify)))
   5912     (setq properties
   5913           (plist-put properties :verify
   5914                      (lambda (checker)
   5915                        (append (flycheck-verify-command-checker checker)
   5916                                (and verify-fn
   5917                                     (funcall verify-fn checker)))))))
   5918 
   5919   (let ((command (plist-get properties :command))
   5920         (patterns (plist-get properties :error-patterns))
   5921         (parser (or (plist-get properties :error-parser)
   5922                     #'flycheck-parse-with-patterns))
   5923         (enabled (plist-get properties :enabled))
   5924         (standard-input (plist-get properties :standard-input)))
   5925     (unless command
   5926       (error "Missing :command in syntax checker %s" symbol))
   5927     (unless (stringp (car command))
   5928       (error "Command executable for syntax checker %s must be a string: %S"
   5929              symbol (car command)))
   5930     (dolist (arg (cdr command))
   5931       (unless (flycheck-command-argument-p arg)
   5932         (error "Invalid command argument %S in syntax checker %s" arg symbol)))
   5933     (when (and (eq parser 'flycheck-parse-with-patterns)
   5934                (not patterns))
   5935       (error "Missing :error-patterns in syntax checker %s" symbol))
   5936 
   5937     (setq properties
   5938           ;; Automatically disable command checkers if the executable does not
   5939           ;; exist.
   5940           (plist-put properties :enabled
   5941                      (lambda ()
   5942                        (and (flycheck-find-checker-executable symbol)
   5943                             (flycheck-temp-files-writable-p symbol)
   5944                             (or (not enabled) (funcall enabled))))))
   5945 
   5946     (apply #'flycheck-define-generic-checker symbol docstring
   5947            :start #'flycheck-start-command-checker
   5948            :interrupt #'flycheck-interrupt-command-checker
   5949            :print-doc #'flycheck-command-checker-print-doc
   5950            properties)
   5951 
   5952     ;; Pre-compile all errors patterns into strings, so that we don't need to do
   5953     ;; that on each error parse
   5954     (let ((patterns (seq-map (lambda (p)
   5955                                (cons (flycheck-rx-to-string `(and ,@(cdr p))
   5956                                                             'no-group)
   5957                                      (car p)))
   5958                              patterns)))
   5959       (pcase-dolist (`(,prop . ,value)
   5960                      `((command        . ,command)
   5961                        (error-parser   . ,parser)
   5962                        (error-patterns . ,patterns)
   5963                        (standard-input . ,standard-input)))
   5964         (setf (flycheck-checker-get symbol prop) value)))))
   5965 
   5966 (eval-and-compile
   5967   ;; Make this function available during byte-compilation, since we need it
   5968   ;; at macro expansion of `flycheck-def-executable-var'.
   5969   (defun flycheck-checker-executable-variable (checker)
   5970     "Get the executable variable of CHECKER.
   5971 
   5972 The executable variable is named `flycheck-CHECKER-executable'."
   5973     (intern (format "flycheck-%s-executable" checker))))
   5974 
   5975 (defun flycheck-checker-default-executable (checker)
   5976   "Get the default executable of CHECKER."
   5977   (car (flycheck-checker-get checker 'command)))
   5978 
   5979 (defun flycheck-checker-executable (checker)
   5980   "Get the command executable of CHECKER.
   5981 
   5982 The executable is either the value of the variable
   5983 `flycheck-CHECKER-executable', or the default executable given in
   5984 the syntax checker definition, if the variable is nil."
   5985   (let ((var (flycheck-checker-executable-variable checker)))
   5986     (or (and (boundp var) (symbol-value var))
   5987         (flycheck-checker-default-executable checker))))
   5988 
   5989 (defun flycheck-find-checker-executable (checker)
   5990   "Get the full path of the executable of CHECKER.
   5991 
   5992 Return the full absolute path to the executable of CHECKER, or
   5993 nil if the executable does not exist."
   5994   (funcall flycheck-executable-find (flycheck-checker-executable checker)))
   5995 
   5996 (defun flycheck-call-checker-process
   5997     (checker infile destination error &rest args)
   5998   "Call CHECKER's executable with ARGS.
   5999 
   6000 Return nil (or raise an error if ERROR is non-nil) when CHECKER's
   6001 executable cannot be found, and return a numeric exit status or a
   6002 signal description string otherwise.  CHECKER's input is taken
   6003 from INFILE, and its output is sent to DESTINATION, as in
   6004 `call-process'."
   6005   (if-let (executable (flycheck-find-checker-executable checker))
   6006       (condition-case err
   6007           (apply #'call-process executable infile destination nil args)
   6008         (error (when error (signal (car err) (cdr err)))))
   6009     (when error
   6010       (user-error "Cannot find `%s' using `flycheck-executable-find'"
   6011                   (flycheck-checker-executable checker)))))
   6012 
   6013 (defun flycheck-call-checker-process-for-output
   6014     (checker infile error &rest args)
   6015   "Call CHECKER's executable with ARGS and return its output.
   6016 
   6017 Call `flycheck-call-checker-process' with INFILE, ERROR, and
   6018 ARGS.  If it returns 0, return the process' output.  Otherwise,
   6019 return nil or throw an error.
   6020 
   6021 This function is similar to `flycheck-call-checker-process'
   6022 called in a `with-output-to-string' block, but it takes care of
   6023 the error checking automatically."
   6024   (let ((temp (generate-new-buffer " *temp*")))
   6025     (unwind-protect
   6026         ;; We need to call the checker process in the right buffer, so that it
   6027         ;; uses the right exec-path, checker executable, etc.  See URL
   6028         ;; `https://github.com/flycheck/flycheck/issues/1770'.
   6029         (let ((exit-code (apply #'flycheck-call-checker-process
   6030                                 checker infile temp error args))
   6031               (output (with-current-buffer temp (buffer-string))))
   6032           (if (eql 0 exit-code) output
   6033             (when error
   6034               (error "Process %s failed with %S (%s)"
   6035                      checker exit-code output))))
   6036       (kill-buffer temp))))
   6037 
   6038 (defun flycheck-checker-arguments (checker)
   6039   "Get the command arguments of CHECKER."
   6040   (cdr (flycheck-checker-get checker 'command)))
   6041 
   6042 (defun flycheck-substitute-argument (arg checker)
   6043   "Substitute ARG for CHECKER.
   6044 
   6045 Return a list of real arguments for the executable of CHECKER,
   6046 substituted for the symbolic argument ARG.  Single arguments,
   6047 e.g. if ARG is a literal strings, are wrapped in a list.
   6048 
   6049 ARG may be one of the following forms:
   6050 
   6051 STRING
   6052      Return ARG unchanged.
   6053 
   6054 `source', `source-inplace'
   6055      Create a temporary file to check and return its path.  With
   6056      `source-inplace' create the temporary file in the same
   6057      directory as the original file.  The value of
   6058      `flycheck-temp-prefix' is used as prefix of the file name.
   6059 
   6060      With `source', try to retain the non-directory component of
   6061      the buffer's file name in the temporary file.
   6062 
   6063      `source' is the preferred way to pass the input file to a
   6064      syntax checker.  `source-inplace' should only be used if the
   6065      syntax checker needs other files from the source directory,
   6066      such as include files in C.
   6067 
   6068 `(source SUFFIX)', `(source-inplace SUFFIX)'
   6069      Like `source' and `source-inplace', but ensure generated
   6070      file names end with the given suffix.  Use this when the
   6071      checker requires that file names on its command line have a
   6072      certain suffix (file extension).
   6073 
   6074 `source-original'
   6075      Return the path of the actual file to check, or an empty
   6076      string if the buffer has no file name.
   6077 
   6078      Note that the contents of the file may not be up to date
   6079      with the contents of the buffer to check.  Do not use this
   6080      as primary input to a checker, unless absolutely necessary.
   6081 
   6082      When using this symbol as primary input to the syntax
   6083      checker, add `flycheck-buffer-saved-p' to the `:predicate'.
   6084 
   6085 `temporary-directory'
   6086      Create a unique temporary directory and return its path.
   6087 
   6088 `temporary-file-name'
   6089      Return a unique temporary filename.  The file is *not*
   6090      created.
   6091 
   6092      To ignore the output of syntax checkers, try symbol
   6093      `null-device' first.
   6094 
   6095 symbol `null-device'
   6096      Return the value of variable `null-device', i.e the system
   6097      null device.
   6098 
   6099      Use this option to ignore the output of a syntax checker.
   6100      If the syntax checker cannot handle the null device, or
   6101      won't write to an existing file, try `temporary-file-name'
   6102      instead.
   6103 
   6104 `(config-file OPTION VARIABLE [PREPEND-FN])'
   6105      Search the configuration file bound to VARIABLE with
   6106      `flycheck-locate-config-file' and return a list of arguments
   6107      that pass this configuration file to the syntax checker, or
   6108      nil if the configuration file was not found.
   6109 
   6110      PREPEND-FN is called with the OPTION and the located
   6111      configuration file, and should return OPTION prepended
   6112      before the file, either a string or as list.  If omitted,
   6113      PREPEND-FN defaults to `list'.
   6114 
   6115 `(option OPTION VARIABLE [PREPEND-FN [FILTER]])'
   6116      Retrieve the value of VARIABLE and return a list of
   6117      arguments that pass this value as value for OPTION to the
   6118      syntax checker.
   6119 
   6120      PREPEND-FN is called with the OPTION and the value of
   6121      VARIABLE, and should return OPTION prepended before the
   6122      file, either a string or as list.  If omitted, PREPEND-FN
   6123      defaults to `list'.
   6124 
   6125      FILTER is an optional function to be applied to the value of
   6126      VARIABLE before prepending.  This function must return nil
   6127      or a string.  In the former case, return nil.  In the latter
   6128      case, return a list of arguments as described above.
   6129 
   6130 `(option-list OPTION VARIABLE [PREPEND-FN [FILTER]])'
   6131      Retrieve the value of VARIABLE, which must be a list,
   6132      and prepend OPTION before each item in this list, using
   6133      PREPEND-FN.
   6134 
   6135      PREPEND-FN is called with the OPTION and each item of the
   6136      list as second argument, and should return OPTION prepended
   6137      before the item, either as string or as list.  If omitted,
   6138      PREPEND-FN defaults to `list'.
   6139 
   6140      FILTER is an optional function to be applied to each item in
   6141      the list before prepending OPTION.  It shall return the
   6142      option value for each item as string, or nil, if the item is
   6143      to be ignored.
   6144 
   6145 `(option-flag OPTION VARIABLE)'
   6146      Retrieve the value of VARIABLE and return OPTION, if the
   6147      value is non-nil.  Otherwise return nil.
   6148 
   6149 `(eval FORM)'
   6150      Return the result of evaluating FORM in the buffer to be
   6151      checked.  FORM must either return a string or a list of
   6152      strings, or nil to indicate that nothing should be
   6153      substituted for CELL.  For all other return types, signal an
   6154      error
   6155 
   6156      _No_ further substitutions are performed, neither in FORM
   6157      before it is evaluated, nor in the result of evaluating
   6158      FORM.
   6159 
   6160 In all other cases, signal an error.
   6161 
   6162 Note that substitution is *not* recursive.  No symbols or cells
   6163 are substituted within the body of cells!"
   6164   (pcase arg
   6165     ((pred stringp) (list arg))
   6166     (`source
   6167      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)))
   6168     (`source-inplace
   6169      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)))
   6170     (`(source ,suffix)
   6171      (list (flycheck-save-buffer-to-temp
   6172             (lambda (filename) (flycheck-temp-file-system filename suffix)))))
   6173     (`(source-inplace ,suffix)
   6174      (list (flycheck-save-buffer-to-temp
   6175             (lambda (filename) (flycheck-temp-file-inplace filename suffix)))))
   6176     (`source-original (list (or (buffer-file-name) "")))
   6177     (`temporary-directory (list (flycheck-temp-dir-system)))
   6178     (`temporary-file-name
   6179      (let ((directory (flycheck-temp-dir-system)))
   6180        (list (make-temp-name (expand-file-name "flycheck" directory)))))
   6181     (`null-device (list null-device))
   6182     (`(config-file ,option-name ,file-name-var)
   6183      (when-let* ((value (symbol-value file-name-var))
   6184                  (file-name (flycheck-locate-config-file value checker)))
   6185        (flycheck-prepend-with-option option-name (list file-name))))
   6186     (`(config-file ,option-name ,file-name-var ,prepend-fn)
   6187      (when-let* ((value (symbol-value file-name-var))
   6188                  (file-name (flycheck-locate-config-file value checker)))
   6189        (flycheck-prepend-with-option option-name (list file-name) prepend-fn)))
   6190     (`(option ,option-name ,variable)
   6191      (when-let (value (symbol-value variable))
   6192        (unless (stringp value)
   6193          (error "Value %S of %S for option %s is not a string"
   6194                 value variable option-name))
   6195        (flycheck-prepend-with-option option-name (list value))))
   6196     (`(option ,option-name ,variable ,prepend-fn)
   6197      (when-let (value (symbol-value variable))
   6198        (unless (stringp value)
   6199          (error "Value %S of %S for option %s is not a string"
   6200                 value variable option-name))
   6201        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
   6202     (`(option ,option-name ,variable ,prepend-fn ,filter)
   6203      (when-let (value (funcall filter (symbol-value variable)))
   6204        (unless (stringp value)
   6205          (error "Value %S of %S (filter: %S) for option %s is not a string"
   6206                 value variable filter option-name))
   6207        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
   6208     (`(option-list ,option-name ,variable)
   6209      (let ((value (symbol-value variable)))
   6210        (unless (and (listp value) (seq-every-p #'stringp value))
   6211          (error "Value %S of %S for option %S is not a list of strings"
   6212                 value variable option-name))
   6213        (flycheck-prepend-with-option option-name value)))
   6214     (`(option-list ,option-name ,variable ,prepend-fn)
   6215      (let ((value (symbol-value variable)))
   6216        (unless (and (listp value) (seq-every-p #'stringp value))
   6217          (error "Value %S of %S for option %S is not a list of strings"
   6218                 value variable option-name))
   6219        (flycheck-prepend-with-option option-name value prepend-fn)))
   6220     (`(option-list ,option-name ,variable ,prepend-fn ,filter)
   6221      (let ((value (delq nil (seq-map filter (symbol-value variable)))))
   6222        (unless (and (listp value) (seq-every-p #'stringp value))
   6223          (error "Value %S of %S for option %S is not a list of strings"
   6224                 value variable option-name))
   6225        (flycheck-prepend-with-option option-name value prepend-fn)))
   6226     (`(option-flag ,option-name ,variable)
   6227      (when (symbol-value variable)
   6228        (list option-name)))
   6229     (`(eval ,form)
   6230      (let ((result (eval form)))
   6231        (cond
   6232         ((and (listp result) (seq-every-p #'stringp result)) result)
   6233         ((stringp result) (list result))
   6234         (t (error "Invalid result from evaluation of %S: %S" form result)))))
   6235     (_ (error "Unsupported argument %S" arg))))
   6236 
   6237 (defun flycheck-checker-substituted-arguments (checker)
   6238   "Get the substituted arguments of a CHECKER.
   6239 
   6240 Substitute each argument of CHECKER using
   6241 `flycheck-substitute-argument'.  This replaces any special
   6242 symbols in the command."
   6243   (apply #'append
   6244          (seq-map (lambda (arg) (flycheck-substitute-argument arg checker))
   6245                   (flycheck-checker-arguments checker))))
   6246 
   6247 (defun flycheck--process-send-buffer-contents-chunked (process)
   6248   "Send contents of current buffer to PROCESS in small batches.
   6249 
   6250 Send the entire buffer to the standard input of PROCESS in chunks
   6251 of 4096 characters.  Chunking is done in Emacs Lisp, hence this
   6252 function is probably far less efficient than
   6253 `send-process-region'.  Use only when required."
   6254   (let ((from (point-min)))
   6255     (while (< from (point-max))
   6256       (let ((to (min (+ from 4096) (point-max))))
   6257         (process-send-region process from to)
   6258         (setq from to)))))
   6259 
   6260 (defvar flycheck-chunked-process-input
   6261   ;; Chunk process output on Windows to work around
   6262   ;; https://github.com/flycheck/flycheck/issues/794 and
   6263   ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344.  The presence of
   6264   ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1) where pipe
   6265   ;; writes on Windows are fixed.
   6266   ;;
   6267   ;; TODO: Remove option and chunking when dropping Emacs 24 support, see
   6268   ;; https://github.com/flycheck/flycheck/issues/856
   6269   (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size)))
   6270   "If non-nil send process input in small chunks.
   6271 
   6272 If this variable is non-nil `flycheck-process-send-buffer' sends
   6273 buffer contents in small chunks.
   6274 
   6275 Defaults to nil, except on Windows to work around Emacs bug
   6276 #22344.")
   6277 
   6278 (defun flycheck-process-send-buffer (process)
   6279   "Send all contents of current buffer to PROCESS.
   6280 
   6281 Sends all contents of the current buffer to the standard input of
   6282 PROCESS, and terminates standard input with EOF.
   6283 
   6284 If `flycheck-chunked-process-input' is non-nil, send buffer
   6285 contents in chunks via
   6286 `flycheck--process-send-buffer-contents-chunked', which see.
   6287 Otherwise use `process-send-region' to send all contents at once
   6288 and rely on Emacs' own buffering and chunking."
   6289   (save-restriction
   6290     (widen)
   6291     (if flycheck-chunked-process-input
   6292         (flycheck--process-send-buffer-contents-chunked process)
   6293       (process-send-region process (point-min) (point-max))))
   6294   (process-send-eof process))
   6295 
   6296 (defun flycheck--wrap-command (prog args)
   6297   "Wrap PROG and ARGS using `flycheck-command-wrapper-function'."
   6298   ;; We don't call `flycheck-executable-find' on the output of the wrapper
   6299   ;; function, since it might not expect it (an executable-find function
   6300   ;; designed to find binaries in a sandbox could get confused if we asked it
   6301   ;; about the sandboxing program itself).
   6302   (funcall flycheck-command-wrapper-function (cons prog args)))
   6303 
   6304 (defun flycheck-start-command-checker (checker callback)
   6305   "Start a command CHECKER with CALLBACK."
   6306   (let (process)
   6307     (condition-case err
   6308         (let* ((program (flycheck-find-checker-executable checker))
   6309                (args (flycheck-checker-substituted-arguments checker))
   6310                (command (flycheck--wrap-command program args))
   6311                (sentinel-events nil)
   6312                ;; Use pipes to receive output from the syntax checker.  They are
   6313                ;; more efficient and more robust than PTYs, which Emacs uses by
   6314                ;; default, and since we don't need any job control features, we
   6315                ;; can easily use pipes.
   6316                (process-connection-type nil))
   6317           ;; We pass do not associate the process with any buffer, by
   6318           ;; passing nil for the BUFFER argument of `start-process'.
   6319           ;; Instead, we just remember the buffer being checked in a
   6320           ;; process property (see below).  This neatly avoids all
   6321           ;; side-effects implied by attached a process to a buffer, which
   6322           ;; may cause conflicts with other packages.
   6323           ;;
   6324           ;; See https://github.com/flycheck/flycheck/issues/298 for an
   6325           ;; example for such a conflict.
   6326           (setq process (apply 'start-process (format "flycheck-%s" checker)
   6327                                nil command))
   6328           ;; Process sentinels can be called while sending input to the process.
   6329           ;; We want to record errors raised by process-send before calling
   6330           ;; `flycheck-handle-signal', so initially just accumulate events.
   6331           (setf (process-sentinel process)
   6332                 (lambda (_ event) (push event sentinel-events)))
   6333           (setf (process-filter process) #'flycheck-receive-checker-output)
   6334           (set-process-query-on-exit-flag process nil)
   6335           ;; Remember the syntax checker, the buffer and the callback
   6336           (process-put process 'flycheck-checker checker)
   6337           (process-put process 'flycheck-callback callback)
   6338           (process-put process 'flycheck-buffer (current-buffer))
   6339           ;; The default directory is bound in the `flycheck-syntax-check-start'
   6340           ;; function.
   6341           (process-put process 'flycheck-working-directory default-directory)
   6342           ;; Track the temporaries created by argument substitution in the
   6343           ;; process itself, to get rid of the global state ASAP.
   6344           (process-put process 'flycheck-temporaries flycheck-temporaries)
   6345           (setq flycheck-temporaries nil)
   6346           ;; Send the buffer to the process on standard input, if enabled.
   6347           (when (flycheck-checker-get checker 'standard-input)
   6348             (condition-case err
   6349                 (flycheck-process-send-buffer process)
   6350               ;; Some checkers exit before reading all input, causing errors
   6351               ;; such as a `file-error' for a closed pipe, or a plain “no longer
   6352               ;; connected to pipe; closed it” error for a disconnection.  We
   6353               ;; report them if needed in `flycheck-finish-checker-process' (see
   6354               ;; `https://github.com/flycheck/flycheck/issues/1278').
   6355               (error (process-put process 'flycheck-error err))))
   6356           ;; Set the actual sentinel and process any events that might have
   6357           ;; happened while we were sending input.
   6358           (setf (process-sentinel process) #'flycheck-handle-signal)
   6359           (dolist (event (nreverse sentinel-events))
   6360             (flycheck-handle-signal process event))
   6361           ;; Return the process.
   6362           process)
   6363       (error
   6364        ;; In case of error, clean up our resources, and report the error back to
   6365        ;; Flycheck.
   6366        (flycheck-safe-delete-temporaries)
   6367        (when process
   6368          ;; No need to explicitly delete the temporary files of the process,
   6369          ;; because deleting runs the sentinel, which will delete them anyway.
   6370          (delete-process process))
   6371        (signal (car err) (cdr err))))))
   6372 
   6373 (defun flycheck-interrupt-command-checker (_checker process)
   6374   "Interrupt a PROCESS."
   6375   ;; Deleting the process always triggers the sentinel, which does the cleanup
   6376   (when process
   6377     (delete-process process)))
   6378 
   6379 (defun flycheck-command-checker-print-doc (checker)
   6380   "Print additional documentation for a command CHECKER."
   6381   (let ((executable (flycheck-checker-default-executable checker))
   6382         (config-file-var (flycheck-checker-get checker 'config-file-var))
   6383         (option-vars (seq-sort #'string<
   6384                                (flycheck-checker-get checker 'option-vars))))
   6385     (princ "\n")
   6386 
   6387     (let ((doc-start (with-current-buffer standard-output (point-max))))
   6388       ;; Track the start of our documentation so that we can re-indent it
   6389       ;; properly
   6390       (princ "  This syntax checker executes \"")
   6391       (princ executable)
   6392       (princ "\"")
   6393       (when config-file-var
   6394         (princ ", using a configuration file from `")
   6395         (princ (symbol-name config-file-var))
   6396         (princ "'"))
   6397       (princ ". The executable can be overridden with `")
   6398       (princ (symbol-name (flycheck-checker-executable-variable checker)))
   6399       (princ "'.")
   6400 
   6401       (with-current-buffer standard-output
   6402         (save-excursion
   6403           (fill-region-as-paragraph doc-start (point-max)))))
   6404     (princ "\n")
   6405     (when option-vars
   6406       (princ
   6407        "\n  This syntax checker can be configured with these options:\n\n")
   6408       (dolist (var option-vars)
   6409         (princ (format "     * `%s'\n" var))))))
   6410 
   6411 (defun flycheck-verify-command-checker (checker)
   6412   "Verify a command CHECKER in the current buffer.
   6413 
   6414 Return a list of `flycheck-verification-result' objects for
   6415 CHECKER."
   6416   (let ((executable (flycheck-find-checker-executable checker))
   6417         (config-file-var (flycheck-checker-get checker 'config-file-var)))
   6418     `(
   6419       ,(flycheck-verification-result-new
   6420         :label "executable"
   6421         :message (if executable (format "Found at %s" executable) "Not found")
   6422         :face (if executable 'success '(bold error)))
   6423       ,@(when config-file-var
   6424           (let* ((value (symbol-value config-file-var))
   6425                  (path (and value (flycheck-locate-config-file value checker))))
   6426             (list (flycheck-verification-result-new
   6427                    :label "configuration file"
   6428                    :message (if path (format "Found at %S" path) "Not found")
   6429                    :face (if path 'success 'warning)))))
   6430       ,@(when (not (flycheck-temp-files-writable-p checker))
   6431           (list (flycheck-verification-result-new
   6432                  :label "temp directory"
   6433                  :message (format "%s is not writable"
   6434                                   (flycheck-temp-directory checker))
   6435                  :face 'error))))))
   6436 
   6437 
   6438 ;;; Process management for command syntax checkers
   6439 (defun flycheck-receive-checker-output (process output)
   6440   "Receive a syntax checking PROCESS OUTPUT."
   6441   (push output (process-get process 'flycheck-pending-output)))
   6442 
   6443 (defun flycheck-get-output (process)
   6444   "Get the complete output of PROCESS."
   6445   (with-demoted-errors "Error while retrieving process output: %S"
   6446     (let ((pending-output (process-get process 'flycheck-pending-output)))
   6447       (apply #'concat (nreverse pending-output)))))
   6448 
   6449 (defun flycheck-handle-signal (process _event)
   6450   "Handle a signal from the syntax checking PROCESS.
   6451 
   6452 _EVENT is ignored."
   6453   (when (memq (process-status process) '(signal exit))
   6454     (let ((files (process-get process 'flycheck-temporaries))
   6455           (buffer (process-get process 'flycheck-buffer))
   6456           (callback (process-get process 'flycheck-callback))
   6457           (cwd (process-get process 'flycheck-working-directory))
   6458           (err (process-get process 'flycheck-error)))
   6459       ;; Delete the temporary files
   6460       (seq-do #'flycheck-safe-delete files)
   6461       (when (buffer-live-p buffer)
   6462         (with-current-buffer buffer
   6463           (condition-case err
   6464               (pcase (process-status process)
   6465                 (`signal
   6466                  (funcall callback 'interrupted))
   6467                 (`exit
   6468                  (flycheck-finish-checker-process
   6469                   (process-get process 'flycheck-checker)
   6470                   (or err (process-exit-status process))
   6471                   files
   6472                   (flycheck-get-output process) callback cwd)))
   6473             ((debug error)
   6474              (funcall callback 'errored (error-message-string err)))))))))
   6475 
   6476 (defun flycheck-finish-checker-process
   6477     (checker exit-status files output callback cwd)
   6478   "Finish a checker process from CHECKER with EXIT-STATUS.
   6479 
   6480 EXIT-STATUS can be a number or an arbitrary form (if it is not 0,
   6481 a `suspicious' status is reported to CALLBACK).
   6482 
   6483 FILES is a list of files given as input to the checker.  OUTPUT
   6484 is the output of the syntax checker.  CALLBACK is the status
   6485 callback to use for reporting.
   6486 
   6487 Parse the OUTPUT and report an appropriate error status.
   6488 
   6489 Resolve all errors in OUTPUT using CWD as working directory."
   6490   (let ((errors (flycheck-parse-output output checker (current-buffer))))
   6491     (when (and (not (equal exit-status 0)) (null errors))
   6492       ;; Warn about a suspicious result from the syntax checker.  We do right
   6493       ;; after parsing the errors, before filtering, because a syntax checker
   6494       ;; might report errors from other files (e.g. includes) even if there
   6495       ;; are no errors in the file being checked.
   6496       (funcall callback 'suspicious
   6497                (format "Flycheck checker %S returned %S, but \
   6498 its output contained no errors: %s\nTry installing a more \
   6499 recent version of %S, and please open a bug report if the issue \
   6500 persists in the latest release.  Thanks!"  checker exit-status
   6501 output checker)))
   6502     (funcall callback 'finished
   6503              ;; Fix error file names, by substituting them backwards from the
   6504              ;; temporaries.
   6505              (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd))
   6506                       errors))))
   6507 
   6508 
   6509 ;;; Executables of command checkers.
   6510 (defmacro flycheck-def-executable-var (checker default-executable)
   6511   "Define the executable variable for CHECKER.
   6512 
   6513 DEFAULT-EXECUTABLE is the default executable.  It is only used in
   6514 the docstring of the variable.
   6515 
   6516 The variable is defined with `defcustom' in the
   6517 `flycheck-executables' group.  It's also defined to be risky as
   6518 file-local variable, to avoid arbitrary executables being used
   6519 for syntax checking."
   6520   (let ((executable-var (flycheck-checker-executable-variable checker)))
   6521     `(progn
   6522        (defcustom ,executable-var nil
   6523          ,(format "The executable of the %s syntax checker.
   6524 
   6525 Either a string containing the name or the path of the
   6526 executable, or nil to use the default executable from the syntax
   6527 checker declaration.
   6528 
   6529 The default executable is %S." checker default-executable)
   6530          :type '(choice (const :tag "Default executable" nil)
   6531                         (string :tag "Name or path"))
   6532          :group 'flycheck-executables
   6533          :risky t))))
   6534 
   6535 (defun flycheck-set-checker-executable (checker &optional executable)
   6536   "Set the executable of CHECKER in the current buffer.
   6537 
   6538 CHECKER is a syntax checker symbol.  EXECUTABLE is a string with
   6539 the name of an executable or the path to an executable file, which
   6540 is to be used as executable for CHECKER.  If omitted or nil,
   6541 reset the executable of CHECKER.
   6542 
   6543 Interactively, prompt for a syntax checker and an executable
   6544 file, and set the executable of the selected syntax checker.
   6545 With prefix arg, prompt for a syntax checker only, and reset the
   6546 executable of the select checker to the default.
   6547 
   6548 Set the executable variable of CHECKER, that is,
   6549 `flycheck-CHECKER-executable' to EXECUTABLE.  Signal
   6550 `user-error', if EXECUTABLE does not denote a command or an
   6551 executable file.
   6552 
   6553 This command is intended for interactive use only.  In Lisp, just
   6554 `let'-bind the corresponding variable, or set it directly.  Use
   6555 `flycheck-checker-executable-variable' to obtain the executable
   6556 variable symbol for a syntax checker."
   6557   (declare (interactive-only "Set the executable variable directly instead"))
   6558   (interactive
   6559    (let* ((checker (flycheck-read-checker "Syntax checker: "))
   6560           (default-executable (flycheck-checker-default-executable checker))
   6561           (executable (if current-prefix-arg
   6562                           nil
   6563                         (read-file-name "Executable: " nil default-executable
   6564                                         nil nil flycheck-executable-find))))
   6565      (list checker executable)))
   6566   (when (and executable (not (funcall flycheck-executable-find executable)))
   6567     (user-error "%s is no executable" executable))
   6568   (let ((variable (flycheck-checker-executable-variable checker)))
   6569     (set (make-local-variable variable) executable)))
   6570 
   6571 
   6572 ;;; Configuration files and options for command checkers
   6573 (defun flycheck-register-config-file-var (var checkers)
   6574   "Register VAR as config file var for CHECKERS.
   6575 
   6576 CHECKERS is a single syntax checker or a list thereof."
   6577   (when (symbolp checkers)
   6578     (setq checkers (list checkers)))
   6579   (dolist (checker checkers)
   6580     (setf (flycheck-checker-get checker 'config-file-var) var)))
   6581 
   6582 ;;;###autoload
   6583 (defmacro flycheck-def-config-file-var (symbol checker &optional file-name
   6584                                                &rest custom-args)
   6585   "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME.
   6586 
   6587 SYMBOL is declared as customizable variable using `defcustom', to
   6588 provide configuration files for the given syntax CHECKER.
   6589 CUSTOM-ARGS are forwarded to `defcustom'.
   6590 
   6591 FILE-NAME is the initial value of the new variable.  If omitted,
   6592 the default value is nil.  It can be either a string or a list of
   6593 strings.
   6594 
   6595 Use this together with the `config-file' form in the `:command'
   6596 argument to `flycheck-define-checker'."
   6597   (declare (indent 3))
   6598   `(progn
   6599      (defcustom ,symbol ,file-name
   6600        ,(format "Configuration file for `%s'.
   6601 
   6602 If set to a string, locate the configuration file using the
   6603 functions from `flycheck-locate-config-file-functions'.  If the
   6604 file is found pass it to the syntax checker as configuration
   6605 file.
   6606 
   6607 If no configuration file is found, or if this variable is set to
   6608 nil, invoke the syntax checker without a configuration file.
   6609 
   6610 Use this variable as file-local variable if you need a specific
   6611 configuration file for a buffer." checker)
   6612        :type '(choice (const :tag "No configuration file" nil)
   6613                       (string :tag "File name or path")
   6614                       (repeat :tag "File names or paths" string))
   6615        :safe #'flycheck-string-or-string-list-p
   6616        :group 'flycheck-config-files
   6617        ,@custom-args)
   6618      (flycheck-register-config-file-var ',symbol ',checker)))
   6619 
   6620 (defun flycheck-locate-config-file (filenames checker)
   6621   "Locate the configuration file for CHECKER, based on FILENAMES.
   6622 
   6623 FILENAMES can be either a single file, or a list.  Each filename
   6624 is passed to all `flycheck-locate-config-file-functions', until
   6625 one returns non-nil.
   6626 
   6627 Return the absolute path of the configuration file, or nil if no
   6628 configuration file was found."
   6629   (when (stringp filenames)
   6630     (setq filenames (list filenames)))
   6631   (let ((config-file nil))
   6632     (while (and filenames (null config-file))
   6633       (setq config-file (run-hook-with-args-until-success
   6634                          'flycheck-locate-config-file-functions
   6635                          (pop filenames) checker)))
   6636     (when (and config-file (file-exists-p config-file))
   6637       config-file)))
   6638 
   6639 (defun flycheck-locate-config-file-by-path (filepath _checker)
   6640   "Locate a configuration file by a FILEPATH.
   6641 
   6642 If FILEPATH is a contains a path separator, expand it against the
   6643 default directory and return it if it points to an existing file.
   6644 Otherwise return nil.
   6645 
   6646 _CHECKER is ignored."
   6647   ;; If the path is just a plain file name, skip it.
   6648   (unless (string= (file-name-nondirectory filepath) filepath)
   6649     (let ((file-name (expand-file-name filepath)))
   6650       (and (file-exists-p file-name) file-name))))
   6651 
   6652 (defun flycheck-locate-config-file-ancestor-directories (filename _checker)
   6653   "Locate a configuration FILENAME in ancestor directories.
   6654 
   6655 If the current buffer has a file name, search FILENAME in the
   6656 directory of the current buffer and all ancestors thereof (see
   6657 `locate-dominating-file').  If the file is found, return its
   6658 absolute path.  Otherwise return nil.
   6659 
   6660 _CHECKER is ignored."
   6661   (when-let* ((basefile (buffer-file-name))
   6662               (directory (locate-dominating-file basefile filename)))
   6663     (expand-file-name filename directory)))
   6664 
   6665 (defun flycheck-locate-config-file-home (filename _checker)
   6666   "Locate a configuration FILENAME in the home directory.
   6667 
   6668 Return the absolute path, if FILENAME exists in the user's home
   6669 directory, or nil otherwise."
   6670   (let ((path (expand-file-name filename "~")))
   6671     (when (file-exists-p path)
   6672       path)))
   6673 
   6674 (seq-do (apply-partially #'custom-add-frequent-value
   6675                          'flycheck-locate-config-file-functions)
   6676         '(flycheck-locate-config-file-by-path
   6677           flycheck-locate-config-file-ancestor-directories
   6678           flycheck-locate-config-file-home))
   6679 
   6680 (defun flycheck-register-option-var (var checkers)
   6681   "Register an option VAR with CHECKERS.
   6682 
   6683 VAR is an option symbol, and CHECKERS a syntax checker symbol or
   6684 a list thereof.  Register VAR with all CHECKERS so that it
   6685 appears in the help output."
   6686   (when (symbolp checkers)
   6687     (setq checkers (list checkers)))
   6688   (dolist (checker checkers)
   6689     (cl-pushnew var (flycheck-checker-get checker 'option-vars))))
   6690 
   6691 ;;;###autoload
   6692 (defmacro flycheck-def-option-var (symbol init-value checkers docstring
   6693                                           &rest custom-args)
   6694   "Define SYMBOL as option variable with INIT-VALUE for CHECKER.
   6695 
   6696 SYMBOL is declared as customizable variable using `defcustom', to
   6697 provide an option for the given syntax CHECKERS (a checker or a
   6698 list of checkers).  INIT-VALUE is the initial value of the
   6699 variable, and DOCSTRING is its docstring.  CUSTOM-ARGS are
   6700 forwarded to `defcustom'.
   6701 
   6702 Use this together with the `option', `option-list' and
   6703 `option-flag' forms in the `:command' argument to
   6704 `flycheck-define-checker'."
   6705   (declare (indent 3)
   6706            (doc-string 4))
   6707   `(progn
   6708      (defcustom ,symbol ,init-value
   6709        ,(concat docstring "
   6710 
   6711 This variable is an option for the following syntax checkers:
   6712 
   6713 "
   6714                 (mapconcat (lambda (c) (format "  - `%s'" c))
   6715                            (if (symbolp checkers) (list checkers) checkers)
   6716                            "\n"))
   6717        :group 'flycheck-options
   6718        ,@custom-args)
   6719      (flycheck-register-option-var ',symbol ',checkers)))
   6720 
   6721 (defun flycheck-option-int (value)
   6722   "Convert an integral option VALUE to a string.
   6723 
   6724 If VALUE is nil, return nil.  Otherwise return VALUE converted to
   6725 a string."
   6726   (and value (number-to-string value)))
   6727 
   6728 (defun flycheck-option-symbol (value)
   6729   "Convert a symbol option VALUE to string.
   6730 
   6731 If VALUE is nil return nil.  Otherwise return VALUE converted to
   6732 a string."
   6733   (and value (symbol-name value)))
   6734 
   6735 (defun flycheck-option-comma-separated-list (value &optional separator filter)
   6736   "Convert VALUE into a list separated by SEPARATOR.
   6737 
   6738 SEPARATOR is a string to separate items in VALUE, defaulting to
   6739 \",\".  FILTER is an optional function, which takes a single
   6740 argument and returns either a string or nil.
   6741 
   6742 If VALUE is a list, apply FILTER to each item in VALUE, remove
   6743 all nil items, and return a single string of all remaining items
   6744 separated by SEPARATOR.
   6745 
   6746 Otherwise, apply FILTER to VALUE and return the result.
   6747 SEPARATOR is ignored in this case."
   6748   (let ((filter (or filter #'identity))
   6749         (separator (or separator ",")))
   6750     (if (listp value)
   6751         (when-let (value (delq nil (seq-map filter value)))
   6752           (string-join value separator))
   6753       (funcall filter value))))
   6754 
   6755 (defmacro flycheck-def-args-var (symbol checkers &rest custom-args)
   6756   "Define SYMBOL as argument variable for CHECKERS.
   6757 
   6758 SYMBOL is declared as customizable, risky and buffer-local
   6759 variable using `defcustom' to provide an option for arbitrary
   6760 arguments for the given syntax CHECKERS (either a single checker
   6761 or a list of checkers).  CUSTOM-ARGS is forwarded to `defcustom'.
   6762 
   6763 Use the `eval' form to splice this variable into the
   6764 `:command'."
   6765   (declare (indent 2))
   6766   `(flycheck-def-option-var ,symbol nil ,checkers
   6767      "A list of additional command line arguments.
   6768 
   6769 The value of this variable is a list of strings with additional
   6770 command line arguments."
   6771      :risky t
   6772      :type '(repeat (string :tag "Argument"))
   6773      ,@custom-args))
   6774 
   6775 
   6776 ;;; Command syntax checkers as compile commands
   6777 (defun flycheck-checker-pattern-to-error-regexp (pattern)
   6778   "Convert PATTERN into an error regexp for compile.el.
   6779 
   6780 Return a list representing PATTERN, suitable as element in
   6781 `compilation-error-regexp-alist'."
   6782   (let* ((regexp (car pattern))
   6783          (level (cdr pattern))
   6784          (level-no (flycheck-error-level-compilation-level level)))
   6785     `(,regexp 1 (2 . 6) (3 . 7) ,level-no)))
   6786 
   6787 (defun flycheck-checker-compilation-error-regexp-alist (checker)
   6788   "Convert error patterns of CHECKER for use with compile.el.
   6789 
   6790 Return an alist of all error patterns of CHECKER, suitable for
   6791 use with `compilation-error-regexp-alist'."
   6792   (seq-map #'flycheck-checker-pattern-to-error-regexp
   6793            (flycheck-checker-get checker 'error-patterns)))
   6794 
   6795 (defun flycheck--substitute-shell-command-argument (arg checker)
   6796   "Substitute ARG for CHECKER.
   6797 
   6798 Like `flycheck-substitute-argument', except for source,
   6799 source-inplace, and source-original."
   6800   (if (memq arg '(source source-inplace source-original))
   6801       (list buffer-file-name)
   6802     (flycheck-substitute-argument arg checker)))
   6803 
   6804 (defun flycheck--checker-substituted-shell-command-arguments (checker)
   6805   "Get the substituted arguments of a CHECKER to run as a shell command.
   6806 
   6807 Substitute each argument of CHECKER using
   6808 `flycheck-substitute-shell-command-argument'."
   6809   (apply #'append
   6810          (seq-map (lambda (arg)
   6811                     (flycheck--substitute-shell-command-argument arg checker))
   6812                   (flycheck-checker-arguments checker))))
   6813 
   6814 (defun flycheck-checker-shell-command (checker)
   6815   "Get a shell command for CHECKER.
   6816 
   6817 Perform substitution in the arguments of CHECKER, but with
   6818 `flycheck--substitute-shell-command-argument'.
   6819 
   6820 Return the command of CHECKER as single string, suitable for
   6821 shell execution."
   6822   ;; Note: Do NOT use `combine-and-quote-strings' here.  Despite it's name it
   6823   ;; does not properly quote shell arguments, and actually breaks for special
   6824   ;; characters.  See https://github.com/flycheck/flycheck/pull/522
   6825   (let* ((args (flycheck--checker-substituted-shell-command-arguments checker))
   6826          (program
   6827           (or (flycheck-find-checker-executable checker)
   6828               (user-error "Cannot find `%s' using `flycheck-executable-find'"
   6829                           (flycheck-checker-executable checker))))
   6830          (wrapped (flycheck--wrap-command program args))
   6831          (abs-prog
   6832           ;; The executable path returned by `flycheck-command-wrapper-function'
   6833           ;; may not be absolute, so expand it here.  See URL
   6834           ;; `https://github.com/flycheck/flycheck/issues/1461'.
   6835           (or (executable-find (car wrapped))
   6836               (user-error "Cannot find `%s' using `executable-find'"
   6837                           (car wrapped))))
   6838          (command (mapconcat #'shell-quote-argument
   6839                              (cons abs-prog (cdr wrapped)) " ")))
   6840     (if (flycheck-checker-get checker 'standard-input)
   6841         ;; If the syntax checker expects the source from standard input add an
   6842         ;; appropriate shell redirection
   6843         (concat command " < " (shell-quote-argument (buffer-file-name)))
   6844       command)))
   6845 
   6846 (defun flycheck-compile-name (_name)
   6847   "Get a name for a Flycheck compilation buffer.
   6848 
   6849 _NAME is ignored."
   6850   (format "*Flycheck %s*" (buffer-file-name)))
   6851 
   6852 (defun flycheck-compile (checker)
   6853   "Run CHECKER via `compile'.
   6854 
   6855 CHECKER must be a valid syntax checker.  Interactively, prompt
   6856 for a syntax checker to run.
   6857 
   6858 Instead of highlighting errors in the buffer, this command pops
   6859 up a separate buffer with the entire output of the syntax checker
   6860 tool, just like `compile' (\\[compile])."
   6861   (interactive
   6862    (let* ((default (flycheck-get-checker-for-buffer))
   6863           (prompt (concat
   6864                    "Run syntax checker as compile command"
   6865                    (when default (concat " [" (format "%S" default) "]"))
   6866                    ": ")))
   6867      (list (flycheck-read-checker prompt
   6868                                   (when (flycheck-checker-get default 'command)
   6869                                     default)
   6870                                   'command))))
   6871   (unless (flycheck-valid-checker-p checker)
   6872     (user-error "%S is not a valid syntax checker" checker))
   6873   (unless (buffer-file-name)
   6874     (user-error "Cannot compile a buffer without a backing file"))
   6875   (unless (flycheck-may-use-checker checker)
   6876     (user-error "Cannot use syntax checker %S in this buffer" checker))
   6877   (unless (flycheck-checker-executable checker)
   6878     (user-error "Cannot run checker %S as shell command" checker))
   6879   (save-some-buffers)
   6880   (let* ((default-directory (flycheck-compute-working-directory checker))
   6881          (command (flycheck-checker-shell-command checker))
   6882          (buffer (compilation-start command nil #'flycheck-compile-name)))
   6883     (with-current-buffer buffer
   6884       (setq-local compilation-error-regexp-alist
   6885                   (flycheck-checker-compilation-error-regexp-alist checker)))))
   6886 
   6887 
   6888 ;;; General error parsing for command checkers
   6889 (defun flycheck-parse-output (output checker buffer)
   6890   "Parse OUTPUT from CHECKER in BUFFER.
   6891 
   6892 OUTPUT is a string with the output from the checker symbol
   6893 CHECKER.  BUFFER is the buffer which was checked.
   6894 
   6895 Return the errors parsed with the error patterns of CHECKER."
   6896   (funcall (flycheck-checker-get checker 'error-parser) output checker buffer))
   6897 
   6898 (defun flycheck-fix-error-filename (err buffer-files cwd)
   6899   "Fix the file name of ERR from BUFFER-FILES.
   6900 
   6901 Resolves error file names relative to CWD directory.
   6902 
   6903 Make the file name of ERR absolute.  If the absolute file name of
   6904 ERR is in BUFFER-FILES, replace it with the value of variable
   6905 `buffer-file-name'."
   6906   (flycheck-error-with-buffer err
   6907     (when-let (filename (flycheck-error-filename err))
   6908       (when (seq-some (apply-partially #'flycheck-same-files-p
   6909                                        (expand-file-name filename cwd))
   6910                       buffer-files)
   6911         (setf (flycheck-error-filename err) buffer-file-name)
   6912         (when (and buffer-file-name (flycheck-error-message err))
   6913           (setf (flycheck-error-message err)
   6914                 (replace-regexp-in-string
   6915                  (regexp-quote filename) buffer-file-name
   6916                  (flycheck-error-message err) 'fixed-case 'literal))))))
   6917   err)
   6918 
   6919 
   6920 ;;; Error parsers for command syntax checkers
   6921 (defun flycheck-parse-xml-region (beg end)
   6922   "Parse the xml region between BEG and END.
   6923 
   6924 Wrapper around `xml-parse-region' which transforms the return
   6925 value of this function into one compatible to
   6926 `libxml-parse-xml-region' by simply returning the first element
   6927 from the node list."
   6928   (ignore-errors (car (xml-parse-region beg end))))
   6929 
   6930 (defun flycheck-parse-xml-region-with-fallback (beg end)
   6931   "Parse the xml region between BEG and END.
   6932 
   6933 Try parsing with libxml first; if that fails, revert to
   6934 `flycheck-parse-xml-region'.  Failures can be caused by incorrect
   6935 XML (see URL `https://github.com/flycheck/flycheck/issues/1298'),
   6936 or on Windows by a missing libxml DLL with a libxml-enabled Emacs
   6937 \(see URL `https://github.com/flycheck/flycheck/issues/1330')."
   6938   ;; FIXME use `libxml-available-p' when it gets implemented.
   6939   (or (and (fboundp 'libxml-parse-xml-region)
   6940            (libxml-parse-xml-region beg end))
   6941       (flycheck-parse-xml-region beg end)))
   6942 
   6943 (defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback
   6944   "Function used to parse an xml string from a region.
   6945 
   6946 The default uses libxml if available, and falls back to
   6947 `flycheck-parse-xml-region' otherwise.")
   6948 
   6949 (defun flycheck-parse-xml-string (xml)
   6950   "Parse an XML string.
   6951 
   6952 Return the document tree parsed from XML in the form `(ROOT ATTRS
   6953 BODY...)'.  ROOT is a symbol identifying the name of the root
   6954 element.  ATTRS is an alist of the attributes of the root node.
   6955 BODY is zero or more body elements, either as strings (in case of
   6956 text nodes) or as XML nodes, in the same for as the root node."
   6957   (with-temp-buffer
   6958     (insert xml)
   6959     (funcall flycheck-xml-parser (point-min) (point-max))))
   6960 
   6961 (defun flycheck-parse-checkstyle (output checker buffer)
   6962   "Parse Checkstyle errors from OUTPUT.
   6963 
   6964 Parse Checkstyle-like XML output.  Use this error parser for
   6965 checkers that have an option to output errors in this format.
   6966 
   6967 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   6968 the BUFFER that was checked respectively.
   6969 
   6970 See URL `https://checkstyle.sourceforge.net/' for information
   6971 about Checkstyle."
   6972   (pcase (flycheck-parse-xml-string output)
   6973     (`(checkstyle ,_ . ,file-nodes)
   6974      (let (errors)
   6975        (dolist (node file-nodes)
   6976          (pcase node
   6977            (`(file ,file-attrs . ,error-nodes)
   6978             (dolist (node error-nodes)
   6979               (pcase node
   6980                 (`(error ,error-attrs . ,_)
   6981                  (let-alist error-attrs
   6982                    (push (flycheck-error-new-at
   6983                           (flycheck-string-to-number-safe .line)
   6984                           (flycheck-string-to-number-safe .column)
   6985                           (pcase .severity
   6986                             (`"error"   'error)
   6987                             (`"warning" 'warning)
   6988                             (`"info"    'info)
   6989                             ;; Default to error for unknown .severity
   6990                             (_          'error))
   6991                           .message
   6992                           :checker checker :id .source
   6993                           :buffer buffer
   6994                           :filename (cdr (assq 'name file-attrs)))
   6995                          errors))))))))
   6996        (nreverse errors)))))
   6997 
   6998 (defun flycheck-parse-cppcheck (output checker buffer)
   6999   "Parse Cppcheck errors from OUTPUT.
   7000 
   7001 Parse Cppcheck XML v2 output.
   7002 
   7003 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7004 the BUFFER that was checked respectively.
   7005 
   7006 See URL `https://cppcheck.sourceforge.net/' for more information
   7007 about Cppcheck."
   7008   (pcase (flycheck-parse-xml-string output)
   7009     (`(results ,_ . ,body)
   7010      (let (errors)
   7011        (dolist (node body)
   7012          (pcase node
   7013            (`(errors ,_ . ,error-nodes)
   7014             (dolist (node error-nodes)
   7015               (pcase node
   7016                 (`(error ,error-attrs . ,loc-nodes)
   7017                  (let ((id (cdr (assq 'id error-attrs)))
   7018                        (message (cdr (assq 'verbose error-attrs)))
   7019                        (level (pcase (cdr (assq 'severity error-attrs))
   7020                                 (`"error" 'error)
   7021                                 (`"style" 'info)
   7022                                 (`"information" 'info)
   7023                                 (_ 'warning))))
   7024                    (dolist (node loc-nodes)
   7025                      (pcase node
   7026                        (`(location ,loc-attrs . ,_)
   7027                         (let-alist loc-attrs
   7028                           (push (flycheck-error-new-at
   7029                                  (flycheck-string-to-number-safe .line)
   7030                                  nil
   7031                                  level
   7032                                  ;; cppcheck return newline characters as "\012"
   7033                                  (replace-regexp-in-string "\\\\012" "\n"
   7034                                                            message)
   7035                                  :id id
   7036                                  :checker checker
   7037                                  :buffer buffer
   7038                                  :filename .file)
   7039                                 errors))))))))))))
   7040        (nreverse errors)))))
   7041 
   7042 (defun flycheck-parse-phpmd (output checker buffer)
   7043   "Parse phpmd errors from OUTPUT.
   7044 
   7045 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7046 the BUFFER that was checked respectively.
   7047 
   7048 See URL `https://phpmd.org/' for more information about phpmd."
   7049   (pcase (flycheck-parse-xml-string output)
   7050     (`(pmd ,_ . ,body)
   7051      (let (errors)
   7052        (dolist (node body)
   7053          (pcase node
   7054            (`(file ,file-attrs . ,violation-nodes)
   7055             (let ((filename (cdr (assq 'name file-attrs))))
   7056               (dolist (node violation-nodes)
   7057                 (pcase node
   7058                   (`(violation ,vio-attrs ,(and message (pred stringp)))
   7059                    (let-alist vio-attrs
   7060                      (push
   7061                       (flycheck-error-new-at
   7062                        (flycheck-string-to-number-safe .beginline)
   7063                        nil
   7064                        'warning (string-trim message)
   7065                        ;; Ignore .endline (phpmd marks giant spans as errors)
   7066                        ;; :end-line (flycheck-string-to-number-safe .endline)
   7067                        :id .rule
   7068                        :checker checker
   7069                        :buffer buffer
   7070                        :filename filename)
   7071                       errors)))))))))
   7072        (nreverse errors)))))
   7073 
   7074 (defun flycheck-parse-reek (output checker buffer)
   7075   "Parse Reek warnings from JSON OUTPUT.
   7076 
   7077 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7078 the BUFFER that was checked respectively.
   7079 
   7080 See URL `https://github.com/troessner/reek' for more information
   7081 about Reek."
   7082   (let ((errors nil))
   7083     (dolist (message (car (flycheck-parse-json output)))
   7084       (let-alist message
   7085         (dolist (line (delete-dups .lines))
   7086           (push
   7087            (flycheck-error-new-at
   7088             line
   7089             nil
   7090             'warning (concat .context " " .message)
   7091             :id .smell_type
   7092             :checker checker
   7093             :buffer buffer
   7094             :filename .source)
   7095            errors))))
   7096     (nreverse errors)))
   7097 
   7098 (defun flycheck-parse-go-staticcheck (output checker buffer)
   7099   "Parse staticheck warnings from JSON OUTPUT.
   7100 
   7101 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7102 the BUFFER that was checked respectively.
   7103 
   7104 See URL `https://staticcheck.io/docs/formatters' for more
   7105 information about staticheck."
   7106   (let ((errors nil))
   7107     (dolist (msg (flycheck-parse-json output))
   7108       (let-alist msg
   7109         (push
   7110          (flycheck-error-new-at
   7111           .location.line
   7112           .location.column
   7113           (pcase .severity
   7114             (`"error"   'error)
   7115             (`"warning" 'warning)
   7116             (`"ignored" 'info)
   7117             ;; Default to warning for unknown .severity
   7118             (_          'warning))
   7119           .message
   7120           :id .code
   7121           :checker checker
   7122           :buffer buffer
   7123           :filename .location.file)
   7124          errors)))
   7125     (nreverse errors)))
   7126 
   7127 (defun flycheck-parse-tslint (output checker buffer)
   7128   "Parse TSLint errors from JSON OUTPUT.
   7129 
   7130 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7131 the BUFFER that was checked respectively.
   7132 
   7133 See URL `https://palantir.github.io/tslint/' for more information
   7134 about TSLint."
   7135   (seq-map (lambda (message)
   7136              (let-alist message
   7137                (flycheck-error-new-at
   7138                 (+ 1 .startPosition.line)
   7139                 (+ 1 .startPosition.character)
   7140                 (pcase .ruleSeverity
   7141                   ("ERROR"   'error)
   7142                   ("WARNING" 'warning)
   7143                   (_         'warning))
   7144                 .failure
   7145                 :id .ruleName
   7146                 :checker checker
   7147                 :buffer buffer
   7148                 :filename .name
   7149                 :end-line (+ 1 .endPosition.line)
   7150                 :end-column (+ 1 .endPosition.character))))
   7151            (car (flycheck-parse-json output))))
   7152 
   7153 (defun flycheck-parse-rust-collect-spans (span)
   7154   "Return a list of spans contained in a SPAN object."
   7155   (let ((spans))
   7156     (let-alist span
   7157       ;; With macro expansion errors, some spans will point to phony file names
   7158       ;; to indicate an error inside the std rust lib.  We skip these spans as
   7159       ;; they won't appear in flycheck anyway.
   7160       (unless (string= .file_name "<std macros>")
   7161         (push span spans))
   7162 
   7163       ;; Macro expansion errors will have a span in the 'expansion' field, so we
   7164       ;; recursively collect it.
   7165       (if .expansion.span
   7166           (append (flycheck-parse-rust-collect-spans .expansion.span)
   7167                   spans)
   7168         spans))))
   7169 
   7170 (defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer)
   7171   "Turn a rustc DIAGNOSTIC into a `flycheck-error'.
   7172 
   7173 CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC
   7174 and the BUFFER that was checked respectively.
   7175 
   7176 DIAGNOSTIC should be a parsed JSON object describing a rustc
   7177 diagnostic, following the format described there:
   7178 
   7179 https://github.com/rust-lang/rust/blob/master/src/librustc_errors/json.rs#L154"
   7180   (let ((error-message)
   7181         (error-level)
   7182         (error-code)
   7183         (primary-filename)
   7184         (primary-line)
   7185         (primary-column)
   7186         (primary-end-line)
   7187         (primary-end-column)
   7188         (group (make-symbol "group"))
   7189         (spans)
   7190         (children)
   7191         (errors))
   7192     ;; The diagnostic format is described in the link above.  The gist of it is
   7193     ;; that a diagnostic can have several causes in the source text; these
   7194     ;; causes are represented by spans.  The diagnostic has a message and a
   7195     ;; level (error, warning), while the spans have a filename, line, column,
   7196     ;; and an optional label.  The primary span points to the root cause of the
   7197     ;; error in the source text, while non-primary spans point to related
   7198     ;; causes.  Spans may have an 'expansion' field for macro expansion errors;
   7199     ;; these expansion fields will contain another span (and so on).  In
   7200     ;; addition, a diagnostic can also have children diagnostics that are used
   7201     ;; to provide additional information through their message field, but do not
   7202     ;; seem to contain any spans (yet).
   7203     ;;
   7204     ;; We first gather spans in order to turn every span into a flycheck error
   7205     ;; object, that we collect into the `errors' list.
   7206 
   7207     ;; Nested `let-alist' cause compilation warnings, hence we `setq' all
   7208     ;; these values here first to avoid nesting.
   7209     (let-alist diagnostic
   7210       (setq error-message .message
   7211             error-level (pcase .level
   7212                           (`"error" 'error)
   7213                           (`"warning" 'warning)
   7214                           (`"note" 'info)
   7215                           (_ 'error))
   7216             ;; The 'code' field of the diagnostic contains the actual error
   7217             ;; code and an optional explanation that we ignore
   7218             error-code .code.code
   7219             ;; Collect all spans recursively
   7220             spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans)
   7221             children .children))
   7222 
   7223     ;; Turn each span into a flycheck error
   7224     (dolist (span spans)
   7225       (let-alist span
   7226         ;; Children may not have filename/line/column information, so we use
   7227         ;; those from the primary span
   7228         (when .is_primary
   7229           (setq primary-filename .file_name
   7230                 primary-line .line_start
   7231                 primary-column .column_start
   7232                 primary-end-line .line_end
   7233                 primary-end-column .column_end))
   7234         (push
   7235          (flycheck-error-new-at
   7236           .line_start
   7237           .column_start
   7238           ;; Non-primary spans are used for notes
   7239           (if .is_primary error-level 'info)
   7240           (if .is_primary
   7241               ;; Primary spans may have labels with additional information
   7242               (concat error-message (when .label
   7243                                       (format " (%s)" .label)))
   7244             ;; If the label is empty, fallback on the error message,
   7245             ;; otherwise we won't be able to display anything
   7246             (or .label error-message))
   7247           :id error-code
   7248           :checker checker
   7249           :buffer buffer
   7250           :filename .file_name
   7251           :group group
   7252           :end-line .line_end
   7253           :end-column .column_end)
   7254          errors)))
   7255 
   7256     ;; Then we turn children messages into flycheck errors pointing to the
   7257     ;; location of the primary span.
   7258     (dolist (child children)
   7259       (let ((message (let-alist child .message)))
   7260         (let-alist (car (let-alist child .spans))
   7261           (push
   7262            (flycheck-error-new-at
   7263             ;; Use the line/column from the first span if there is one, or
   7264             ;; fallback to the line/column information from the primary span of
   7265             ;; the diagnostic.
   7266             (or .line_start primary-line)
   7267             (or .column_start primary-column)
   7268             'info
   7269             ;; Messages from `cargo clippy' may suggest replacement code.  In
   7270             ;; these cases, the `message' field itself is an unhelpful `try' or
   7271             ;; `change this to'.  We add the `suggested_replacement' field in
   7272             ;; these cases.
   7273             (if .suggested_replacement
   7274                 (format "%s: `%s`" message .suggested_replacement)
   7275               message)
   7276             :id error-code
   7277             :checker checker
   7278             :buffer buffer
   7279             :filename primary-filename
   7280             :group group
   7281             :end-line (or .line_end primary-end-line)
   7282             :end-column (or .column_end primary-end-column))
   7283            errors))))
   7284 
   7285     ;; If there are no spans, the error is not associated with a specific
   7286     ;; file but with the project as a whole.  We still need to report it to
   7287     ;; the user by emitting a corresponding flycheck-error object.
   7288     ;; Check whether the code is non-nil because Rust≥1.44 includes the
   7289     ;; warning count upon completion.
   7290     (when (and error-code (not spans))
   7291       (push (flycheck-error-new-at
   7292              ;; We have no specific position to attach the error to, so
   7293              ;; let's use the top of the file.
   7294              1 1
   7295              error-level
   7296              error-message
   7297              :id error-code
   7298              :checker checker
   7299              :buffer buffer
   7300              :group group)
   7301             errors))
   7302     (nreverse errors)))
   7303 
   7304 (defconst flycheck--json-parser
   7305   (if (and (functionp 'json-parse-buffer)
   7306            ;; json-parse-buffer only supports keyword arguments in Emacs 27+
   7307            (>= emacs-major-version 27))
   7308       (lambda ()
   7309         (json-parse-buffer
   7310          :object-type 'alist :array-type 'list
   7311          :null-object nil :false-object nil))
   7312     #'json-read)
   7313   "Function to use to parse JSON strings.")
   7314 
   7315 (defun flycheck-parse-json (output)
   7316   "Return parsed JSON data from OUTPUT.
   7317 
   7318 OUTPUT is a string that contains JSON data.  Each line of OUTPUT
   7319 may be either plain text, a JSON array (starting with `['), or a
   7320 JSON object (starting with `{').
   7321 
   7322 This function ignores the plain text lines, parses the JSON
   7323 lines, and returns the parsed JSON lines in a list."
   7324   (let ((objects nil)
   7325         (json-array-type 'list)
   7326         (json-false nil))
   7327     (with-temp-buffer
   7328       (insert output)
   7329       (goto-char (point-min))
   7330       (while (not (eobp))
   7331         (when (memq (char-after) '(?\{ ?\[))
   7332           (push (funcall flycheck--json-parser) objects))
   7333         (forward-line)))
   7334     (nreverse objects)))
   7335 
   7336 (defun flycheck-parse-rustc (output checker buffer)
   7337   "Parse rustc errors from OUTPUT and return a list of `flycheck-error'.
   7338 
   7339 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7340 the BUFFER that was checked respectively.
   7341 
   7342 The expected format for OUTPUT is a mix of plain text lines and
   7343 JSON lines.  This function ignores the plain text lines and
   7344 parses only JSON lines.  Each JSON line is expected to be a JSON
   7345 object that corresponds to a diagnostic from the compiler.  The
   7346 expected diagnostic format is described there:
   7347 
   7348 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
   7349   (seq-mapcat (lambda (msg)
   7350                 (flycheck-parse-rustc-diagnostic msg checker buffer))
   7351               (flycheck-parse-json output)))
   7352 
   7353 (defun flycheck-parse-cargo-rustc (output checker buffer)
   7354   "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'.
   7355 
   7356 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7357 the BUFFER that was checked respectively.
   7358 
   7359 The expected format for OUTPUT is a mix of plain text lines and
   7360 JSON lines.  This function ignores the plain text lines and
   7361 parses only JSON lines.  Each JSON line is expected to be a JSON
   7362 object that represents a message from Cargo.  The format of
   7363 messages emitted by Cargo is described in cargo's
   7364 machine_message.rs at URL `https://git.io/vh24R'."
   7365   (let ((errors))
   7366     (dolist (msg (flycheck-parse-json output))
   7367       (let-alist msg
   7368         ;; Errors and warnings from rustc are wrapped by cargo, so we filter and
   7369         ;; unwrap them, and delegate the actual construction of `flycheck-error'
   7370         ;; objects to `flycheck-parse-rustc-diagnostic'.
   7371         ;; We put the error record with nil code since flycheck regards
   7372         ;; the case of nonzero return code without any error report
   7373         ;; as abnormal result.
   7374         (when (string= .reason "compiler-message")
   7375           (push (flycheck-parse-rustc-diagnostic .message checker buffer)
   7376                 errors))))
   7377     (apply #'nconc errors)))
   7378 
   7379 ;; Some checkers output ANSI terminal colors, which don't match up
   7380 ;; with :error-patterns, so we strip those color codes from the output
   7381 ;; here before passing it along to the default behavior. This is
   7382 ;; originally only used in the rebar3 checker, but the systemd checker
   7383 ;; now also makes use of it.
   7384 ;;
   7385 ;; The relevant discussion can be found at
   7386 ;; https://github.com/flycheck/flycheck/pull/1144
   7387 (defun flycheck-parse-with-patterns-without-color (output checker buffer)
   7388   "Strip color codes from OUTPUT before passing it to the default behavior.
   7389 
   7390 CHECKER and BUFFER are passed along as well."
   7391   (flycheck-parse-with-patterns
   7392    (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
   7393    checker buffer))
   7394 
   7395 
   7396 ;;; Error parsing with regular expressions
   7397 (defun flycheck-get-regexp (patterns)
   7398   "Create a single regular expression from PATTERNS."
   7399   (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns))
   7400                 'no-group))
   7401 
   7402 (defun flycheck-tokenize-output-with-patterns (output patterns)
   7403   "Tokenize OUTPUT with PATTERNS.
   7404 
   7405 Split the output into error tokens, using all regular expressions
   7406 from the error PATTERNS.  An error token is simply a string
   7407 containing a single error from OUTPUT.  Such a token can then be
   7408 parsed into a structured error by applying the PATTERNS again,
   7409 see `flycheck-parse-error-with-patterns'.
   7410 
   7411 Return a list of error tokens."
   7412   (let ((regexp (flycheck-get-regexp patterns))
   7413         (last-match 0)
   7414         errors)
   7415     (while (string-match regexp output last-match)
   7416       (push (match-string 0 output) errors)
   7417       (setq last-match (match-end 0)))
   7418     (reverse errors)))
   7419 
   7420 (defun flycheck-try-parse-error-with-pattern (err pattern checker)
   7421   "Try to parse a single ERR with a PATTERN for CHECKER.
   7422 
   7423 Return the parsed error if PATTERN matched ERR, or nil
   7424 otherwise.
   7425 
   7426 `end-line' defaults to the value of `line' when `end-column' is
   7427 set, since checkers often omit redundant end lines (as in
   7428 <file>:<line>:<column>-<end-column>)."
   7429   (let ((regexp (car pattern))
   7430         (level (cdr pattern)))
   7431     (when (string-match regexp err)
   7432       (let ((filename (match-string 1 err))
   7433             (line (flycheck-string-to-number-safe (match-string 2 err)))
   7434             (column (flycheck-string-to-number-safe (match-string 3 err)))
   7435             (message (match-string 4 err))
   7436             (id (match-string 5 err))
   7437             (end-line (flycheck-string-to-number-safe (match-string 6 err)))
   7438             (end-column (flycheck-string-to-number-safe (match-string 7 err))))
   7439         (flycheck-error-new-at
   7440          line
   7441          column
   7442          level
   7443          (unless (string-empty-p message) message)
   7444          :id (unless (string-empty-p id) id)
   7445          :checker checker
   7446          :filename (if (or (null filename) (string-empty-p filename))
   7447                        (buffer-file-name)
   7448                      filename)
   7449          :end-line (or end-line (and end-column line))
   7450          :end-column end-column)))))
   7451 
   7452 (defun flycheck-parse-error-with-patterns (err patterns checker)
   7453   "Parse a single ERR with error PATTERNS for CHECKER.
   7454 
   7455 Apply each pattern in PATTERNS to ERR, in the given order, and
   7456 return the first parsed error."
   7457   ;; Try to parse patterns in the order of declaration to make sure that the
   7458   ;; first match wins.
   7459   (let (parsed-error)
   7460     (while (and patterns
   7461                 (not (setq parsed-error
   7462                            (flycheck-try-parse-error-with-pattern
   7463                             err (car patterns) checker))))
   7464       (setq patterns (cdr patterns)))
   7465     parsed-error))
   7466 
   7467 (defun flycheck-parse-with-patterns (output checker buffer)
   7468   "Parse OUTPUT from CHECKER with error patterns.
   7469 
   7470 Uses the error patterns of CHECKER to tokenize the output and
   7471 tries to parse each error token with all patterns, in the order
   7472 of declaration.  Hence an error is never matched twice by two
   7473 different patterns.  The pattern declared first always wins.
   7474 
   7475 _BUFFER is ignored.
   7476 
   7477 Return a list of parsed errors and warnings (as `flycheck-error'
   7478 objects)."
   7479   (with-current-buffer buffer
   7480     (let ((patterns (flycheck-checker-get checker 'error-patterns)))
   7481       (seq-map (lambda (err)
   7482                  (flycheck-parse-error-with-patterns err patterns checker))
   7483                (flycheck-tokenize-output-with-patterns output patterns)))))
   7484 
   7485 
   7486 ;;; Convenience definition of command-syntax checkers
   7487 
   7488 ;; This macro is autoloaded to prevent `with-eval-after-load' from expanding its
   7489 ;; arguments.  See https://github.com/flycheck/flycheck/issues/1398.
   7490 ;;;###autoload
   7491 (defmacro flycheck-define-checker (symbol docstring &rest properties)
   7492   "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES.
   7493 
   7494 Like `flycheck-define-command-checker', but PROPERTIES must not
   7495 be quoted.  Also, implicitly define the executable variable for
   7496 SYMBOL with `flycheck-def-executable-var'."
   7497   (declare (indent 1)
   7498            (doc-string 2))
   7499   (let ((command (plist-get properties :command))
   7500         (parser (plist-get properties :error-parser))
   7501         (filter (plist-get properties :error-filter))
   7502         (explainer (plist-get properties :error-explainer))
   7503         (predicate (plist-get properties :predicate))
   7504         (enabled-fn (plist-get properties :enabled))
   7505         (verify-fn (plist-get properties :verify)))
   7506 
   7507     `(progn
   7508        (flycheck-def-executable-var ,symbol ,(car command))
   7509 
   7510        (flycheck-define-command-checker ',symbol
   7511          ,docstring
   7512          :command ',command
   7513          ,@(when parser
   7514              `(:error-parser #',parser))
   7515          :error-patterns ',(plist-get properties :error-patterns)
   7516          ,@(when filter
   7517              `(:error-filter #',filter))
   7518          ,@(when explainer
   7519              `(:error-explainer #',explainer))
   7520          :modes ',(plist-get properties :modes)
   7521          ,@(when predicate
   7522              `(:predicate #',predicate))
   7523          :next-checkers ',(plist-get properties :next-checkers)
   7524          ,@(when enabled-fn
   7525              `(:enabled #',enabled-fn))
   7526          ,@(when verify-fn
   7527              `(:verify #',verify-fn))
   7528          :standard-input ',(plist-get properties :standard-input)
   7529          :working-directory ',(plist-get properties :working-directory)))))
   7530 
   7531 
   7532 ;;; Built-in checkers
   7533 (flycheck-def-args-var flycheck-gnat-args ada-gnat
   7534   :package-version '(flycheck . "0.20"))
   7535 
   7536 (flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat
   7537   "A list of include directories for GNAT.
   7538 
   7539 The value of this variable is a list of strings, where each
   7540 string is a directory to add to the include path of gcc.
   7541 Relative paths are relative to the file being checked."
   7542   :type '(repeat (directory :tag "Include directory"))
   7543   :safe #'flycheck-string-list-p
   7544   :package-version '(flycheck . "0.20"))
   7545 
   7546 (flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat
   7547   "The language standard to use in GNAT.
   7548 
   7549 The value of this variable is either a string denoting a language
   7550 standard, or nil, to use the default standard. When non-nil, pass
   7551 the language standard via the `-std' option."
   7552   :type '(choice (const :tag "Default standard" nil)
   7553                  (string :tag "Language standard"))
   7554   :safe #'flycheck-string-or-nil-p
   7555   :package-version '(flycheck . "0.20"))
   7556 
   7557 (flycheck-def-option-var flycheck-gnat-warnings
   7558     '("wa") ada-gnat
   7559   "A list of additional Ada warnings to enable in GNAT.
   7560 
   7561 The value of this variable is a list of strings, where each
   7562 string is the name of a warning category to enable. By default,
   7563 most optional warnings are recommended, as in `-gnata'.
   7564 
   7565 Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for
   7566 more information about GNAT warnings."
   7567   :type '(repeat :tag "Warnings" (string :tag "Warning name"))
   7568   :safe #'flycheck-string-list-p
   7569   :package-version '(flycheck . "0.20"))
   7570 
   7571 (flycheck-define-checker ada-gnat
   7572   "An Ada syntax checker using GNAT.
   7573 
   7574 Uses the GNAT compiler from GCC.  See URL
   7575 `https://www.adacore.com/community/'."
   7576   :command ("gnatmake"
   7577             "-c"                        ; Just compile, don't bind
   7578             "-f"                        ; Force re-compilation
   7579             "-u"                        ; Compile the main file only
   7580             "-gnatf"                    ; Full error information
   7581             "-gnatef"                   ; Full source file name
   7582             "-D" temporary-directory
   7583             (option-list "-gnat" flycheck-gnat-warnings concat)
   7584             (option-list "-I" flycheck-gnat-include-path concat)
   7585             (option "-gnat" flycheck-gnat-language-standard concat)
   7586             (eval flycheck-gnat-args)
   7587             source)
   7588   :error-patterns
   7589   ((error line-start
   7590           (message "In file included from") " " (file-name) ":" line ":"
   7591           column ":"
   7592           line-end)
   7593    (info line-start (file-name) ":" line ":" column
   7594          ": note: " (message) line-end)
   7595    (warning line-start (file-name) ":" line ":" column
   7596             ": warning: " (message) line-end)
   7597    ;; no specific error prefix in Ada
   7598    (error line-start (file-name) ":" line ":" column
   7599           ": " (message) line-end))
   7600   :modes ada-mode)
   7601 
   7602 (flycheck-define-checker asciidoc
   7603   "A AsciiDoc syntax checker using the AsciiDoc compiler.
   7604 
   7605 See URL `https://www.methods.co.nz/asciidoc'."
   7606   :command ("asciidoc" "-o" null-device "-")
   7607   :standard-input t
   7608   :error-patterns
   7609   ((error line-start
   7610           "asciidoc: ERROR: <stdin>: Line " line ": " (message)
   7611           line-end)
   7612    (warning line-start
   7613             "asciidoc: WARNING: <stdin>: Line " line ": " (message)
   7614             line-end)
   7615    (info line-start
   7616          "asciidoc: DEPRECATED: <stdin>: Line " line ": " (message)
   7617          line-end))
   7618   :modes adoc-mode)
   7619 
   7620 (flycheck-define-checker asciidoctor
   7621   "An AsciiDoc syntax checker using the Asciidoctor compiler.
   7622 
   7623 See URL `https://asciidoctor.org'."
   7624   :command ("asciidoctor" "-o" null-device "-")
   7625   :standard-input t
   7626   :error-patterns
   7627   ((error line-start
   7628           "asciidoctor: ERROR: <stdin>: Line " line ": " (message)
   7629           line-end)
   7630    (warning line-start
   7631             "asciidoctor: WARNING: <stdin>: Line " line ": " (message)
   7632             line-end))
   7633   :modes adoc-mode)
   7634 
   7635 (defun flycheck-awk-gawk-fix-message (err)
   7636   "Remove the repeated file-name/line from the error message of ERR."
   7637   (setf (flycheck-error-message err)
   7638         (replace-regexp-in-string
   7639          (rx line-start
   7640              (group (zero-or-more (any " " "\t")))
   7641              (group (zero-or-more nonl) "\n")
   7642              (backref 1))
   7643          "\\2"
   7644          (replace-regexp-in-string
   7645           (rx "\ngawk: " (zero-or-more (not (any " "))) ":")
   7646           "\n"
   7647           (flycheck-error-message err))))
   7648   err)
   7649 
   7650 (defun flycheck-awk-gawk-error-filter (errors)
   7651   "Remove repeated file-name/line from ERRORS."
   7652   (seq-do #'flycheck-awk-gawk-fix-message errors)
   7653   errors)
   7654 
   7655 (flycheck-define-checker awk-gawk
   7656   "GNU awk's built-in --lint checker."
   7657   :command ("gawk"
   7658             ;; Avoid code execution.  See https://github.com/w0rp/ale/pull/1411
   7659             "--source" "'BEGIN{exit} END{exit 1}'"
   7660             "-f" source
   7661             "--lint"
   7662             "/dev/null")
   7663   :standard-input nil
   7664   :error-patterns
   7665   ((warning line-start
   7666             "gawk: "
   7667             (file-name) ":" line ":" (optional column ":")
   7668             (message (one-or-more not-newline)
   7669                      (optional "\n"
   7670                                (one-or-more not-newline)
   7671                                " ^ "
   7672                                (one-or-more not-newline)))
   7673             line-end))
   7674   :error-filter flycheck-awk-gawk-error-filter
   7675   :modes awk-mode)
   7676 
   7677 (flycheck-define-checker bazel-build-buildifier
   7678   "A checker for Bazel BUILD and BUILD.bazel files using buildifier.
   7679 
   7680 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7681   :command ("buildifier" "-lint=warn" "--type=build")
   7682   :standard-input t
   7683   :error-patterns
   7684   ((error line-start
   7685           "<stdin>:" line ":" column ": " (message)
   7686           line-end)
   7687    (warning line-start
   7688             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7689             line-end))
   7690   :modes bazel-build-mode)
   7691 
   7692 (flycheck-define-checker bazel-module-buildifier
   7693   "A checker for Bazel MODULE.bazel files using buildifier.
   7694 
   7695 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7696   :command ("buildifier" "-lint=warn" "--type=default")
   7697   :standard-input t
   7698   :error-patterns
   7699   ((error line-start
   7700           "<stdin>:" line ":" column ": " (message)
   7701           line-end)
   7702    (warning line-start
   7703             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7704             line-end))
   7705   :modes bazel-module-mode)
   7706 
   7707 (flycheck-define-checker bazel-starlark-buildifier
   7708   "A checker for Starlark bzl files using buildifier.
   7709 
   7710 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7711   :command ("buildifier" "-lint=warn" "--type=bzl")
   7712   :standard-input t
   7713   :error-patterns
   7714   ((error line-start
   7715           "<stdin>:" line ":" column ": " (message)
   7716           line-end)
   7717    (warning line-start
   7718             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7719             line-end))
   7720   :modes bazel-starlark-mode)
   7721 
   7722 (flycheck-define-checker bazel-workspace-buildifier
   7723   "A checker for Bazel WORKSPACE and WORKSPACE.bazel files using buildifier.
   7724 
   7725 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7726   :command ("buildifier" "-lint=warn" "--type=workspace")
   7727   :standard-input t
   7728   :error-patterns
   7729   ((error line-start
   7730           "<stdin>:" line ":" column ": " (message)
   7731           line-end)
   7732    (warning line-start
   7733             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7734             line-end))
   7735   :modes bazel-workspace-mode)
   7736 
   7737 (flycheck-def-args-var flycheck-clang-args c/c++-clang
   7738   :package-version '(flycheck . "0.22"))
   7739 
   7740 (flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang
   7741   "Enable blocks in Clang.
   7742 
   7743 When non-nil, enable blocks in Clang with `-fblocks'.  See URL
   7744 `https://clang.llvm.org/docs/BlockLanguageSpec.html' for more
   7745 information about blocks."
   7746   :type 'boolean
   7747   :safe #'booleanp
   7748   :package-version '(flycheck . "0.20"))
   7749 
   7750 (flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang
   7751   "Additional preprocessor definitions for Clang.
   7752 
   7753 The value of this variable is a list of strings, where each
   7754 string is an additional definition to pass to Clang, via the `-D'
   7755 option."
   7756   :type '(repeat (string :tag "Definition"))
   7757   :safe #'flycheck-string-list-p
   7758   :package-version '(flycheck . "0.15"))
   7759 
   7760 (flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang
   7761   "A list of include directories for Clang.
   7762 
   7763 The value of this variable is a list of strings, where each
   7764 string is a directory to add to the include path of Clang.
   7765 Relative paths are relative to the file being checked."
   7766   :type '(repeat (directory :tag "Include directory"))
   7767   :safe #'flycheck-string-list-p
   7768   :package-version '(flycheck . "0.14"))
   7769 
   7770 (flycheck-def-option-var flycheck-clang-includes nil c/c++-clang
   7771   "A list of additional include files for Clang.
   7772 
   7773 The value of this variable is a list of strings, where each
   7774 string is a file to include before syntax checking.  Relative
   7775 paths are relative to the file being checked."
   7776   :type '(repeat (file :tag "Include file"))
   7777   :safe #'flycheck-string-list-p
   7778   :package-version '(flycheck . "0.15"))
   7779 
   7780 (flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang
   7781   "The language standard to use in Clang.
   7782 
   7783 The value of this variable is either a string denoting a language
   7784 standard, or nil, to use the default standard.  When non-nil,
   7785 pass the language standard via the `-std' option."
   7786   :type '(choice (const :tag "Default standard" nil)
   7787                  (string :tag "Language standard"))
   7788   :safe #'flycheck-string-or-nil-p
   7789   :package-version '(flycheck . "0.15"))
   7790 (make-variable-buffer-local 'flycheck-clang-language-standard)
   7791 
   7792 (flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang
   7793   "Whether to enable Microsoft extensions to C/C++ in Clang.
   7794 
   7795 When non-nil, enable Microsoft extensions to C/C++ via
   7796 `-fms-extensions'."
   7797   :type 'boolean
   7798   :safe #'booleanp
   7799   :package-version '(flycheck . "0.16"))
   7800 
   7801 (flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang
   7802   "Whether to disable exceptions in Clang.
   7803 
   7804 When non-nil, disable exceptions for syntax checks, via
   7805 `-fno-exceptions'."
   7806   :type 'boolean
   7807   :safe #'booleanp
   7808   :package-version '(flycheck . "0.20"))
   7809 
   7810 (flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang
   7811   "Whether to disable RTTI in Clang.
   7812 
   7813 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
   7814   :type 'boolean
   7815   :safe #'booleanp
   7816   :package-version '(flycheck . "0.15"))
   7817 
   7818 (flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang
   7819   "Whether to warn about language extensions in Clang.
   7820 
   7821 For ISO C, follows the version specified by any -std option used.
   7822 When non-nil, disable non-ISO extensions to C/C++ via
   7823 `-pedantic'."
   7824   :type 'boolean
   7825   :safe #'booleanp
   7826   :package-version '(flycheck . "0.23"))
   7827 
   7828 (flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang
   7829   "Whether to error on language extensions in Clang.
   7830 
   7831 For ISO C, follows the version specified by any -std option used.
   7832 When non-nil, disable non-ISO extensions to C/C++ via
   7833 `-pedantic-errors'."
   7834   :type 'boolean
   7835   :safe #'booleanp
   7836   :package-version '(flycheck . "0.23"))
   7837 
   7838 (flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang
   7839   "The standard library to use for Clang.
   7840 
   7841 The value of this variable is the name of a standard library as
   7842 string, or nil to use the default standard library.
   7843 
   7844 Refer to the Clang manual at URL
   7845 `https://clang.llvm.org/docs/UsersManual.html' for more
   7846 information about the standard library."
   7847   :type '(choice (const :tag "Default standard library" nil)
   7848                  (const "libc++")
   7849                  (const :tag "GNU libstdc++" "libstdc++")
   7850                  (string :tag "Library name"))
   7851   :safe #'flycheck-string-or-nil-p
   7852   :package-version '(flycheck . "0.15"))
   7853 
   7854 (flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang
   7855   "A list of additional warnings to enable in Clang.
   7856 
   7857 The value of this variable is a list of strings, where each string
   7858 is the name of a warning category to enable.  By default, all
   7859 recommended warnings and some extra warnings are enabled (as by
   7860 `-Wall' and `-Wextra' respectively).
   7861 
   7862 Refer to the Clang manual at URL
   7863 `https://clang.llvm.org/docs/UsersManual.html' for more
   7864 information about warnings."
   7865   :type '(choice (const :tag "No additional warnings" nil)
   7866                  (repeat :tag "Additional warnings"
   7867                          (string :tag "Warning name")))
   7868   :safe #'flycheck-string-list-p
   7869   :package-version '(flycheck . "0.14"))
   7870 
   7871 (defun flycheck-c/c++-quoted-include-directory ()
   7872   "Get the directory for quoted includes.
   7873 
   7874 C/C++ compilers typically look up includes with quotation marks
   7875 in the directory of the file being compiled.  However, since
   7876 Flycheck uses temporary copies for syntax checking, it needs to
   7877 explicitly determine the directory for quoted includes.
   7878 
   7879 This function determines the directory by looking at function
   7880 `buffer-file-name', or if that is nil, at `default-directory'."
   7881   (if-let (fn (buffer-file-name))
   7882       (file-name-directory fn)
   7883     ;; If the buffer has no file name, fall back to its default directory
   7884     default-directory))
   7885 
   7886 (flycheck-define-checker c/c++-clang
   7887   "A C/C++ syntax checker using Clang.
   7888 
   7889 See URL `https://clang.llvm.org/'."
   7890   :command ("clang"
   7891             "-fsyntax-only"
   7892             "-fno-color-diagnostics"    ; Do not include color codes in output
   7893             "-fno-caret-diagnostics"    ; Do not visually indicate the source
   7894                                         ; location
   7895             "-fno-diagnostics-show-option" ; Do not show the corresponding
   7896                                         ; warning group
   7897             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   7898             (option "-std=" flycheck-clang-language-standard concat)
   7899             (option-flag "-pedantic" flycheck-clang-pedantic)
   7900             (option-flag "-pedantic-errors" flycheck-clang-pedantic-errors)
   7901             (option "-stdlib=" flycheck-clang-standard-library concat)
   7902             (option-flag "-fms-extensions" flycheck-clang-ms-extensions)
   7903             (option-flag "-fno-exceptions" flycheck-clang-no-exceptions)
   7904             (option-flag "-fno-rtti" flycheck-clang-no-rtti)
   7905             (option-flag "-fblocks" flycheck-clang-blocks)
   7906             (option-list "-include" flycheck-clang-includes)
   7907             (option-list "-W" flycheck-clang-warnings concat)
   7908             (option-list "-D" flycheck-clang-definitions concat)
   7909             (option-list "-I" flycheck-clang-include-path)
   7910             (eval flycheck-clang-args)
   7911             "-x" (eval
   7912                   (pcase major-mode
   7913                     ((or `c++-mode `c++-ts-mode) "c++")
   7914                     ((or `c-mode `c-ts-mode) "c")))
   7915             ;; Read from standard input
   7916             "-")
   7917   :standard-input t
   7918   :error-patterns
   7919   ((info line-start (or "<stdin>" (file-name)) ":" line ":" column
   7920          ": note: " (optional (message)) line-end)
   7921    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
   7922             ": warning: " (optional (message)) line-end)
   7923    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
   7924           ": " (or "fatal error" "error") ": " (optional (message)) line-end))
   7925   :error-filter
   7926   (lambda (errors)
   7927     (let ((errors (flycheck-sanitize-errors errors)))
   7928       (dolist (err errors)
   7929         ;; Clang will output empty messages for #error/#warning pragmas without
   7930         ;; messages.  We fill these empty errors with a dummy message to get
   7931         ;; them past our error filtering
   7932         (setf (flycheck-error-message err)
   7933               (or (flycheck-error-message err) "no message")))
   7934       errors))
   7935   :modes (c-mode c++-mode c-ts-mode c++-ts-mode)
   7936   :next-checkers ((warning . c/c++-cppcheck)))
   7937 
   7938 (flycheck-def-args-var flycheck-gcc-args c/c++-gcc
   7939   :package-version '(flycheck . "0.22"))
   7940 
   7941 (flycheck-def-option-var flycheck-gcc-definitions nil c/c++-gcc
   7942   "Additional preprocessor definitions for GCC.
   7943 
   7944 The value of this variable is a list of strings, where each
   7945 string is an additional definition to pass to GCC, via the `-D'
   7946 option."
   7947   :type '(repeat (string :tag "Definition"))
   7948   :safe #'flycheck-string-list-p
   7949   :package-version '(flycheck . "0.20"))
   7950 
   7951 (flycheck-def-option-var flycheck-gcc-include-path nil c/c++-gcc
   7952   "A list of include directories for GCC.
   7953 
   7954 The value of this variable is a list of strings, where each
   7955 string is a directory to add to the include path of gcc.
   7956 Relative paths are relative to the file being checked."
   7957   :type '(repeat (directory :tag "Include directory"))
   7958   :safe #'flycheck-string-list-p
   7959   :package-version '(flycheck . "0.20"))
   7960 
   7961 (flycheck-def-option-var flycheck-gcc-includes nil c/c++-gcc
   7962   "A list of additional include files for GCC.
   7963 
   7964 The value of this variable is a list of strings, where each
   7965 string is a file to include before syntax checking.  Relative
   7966 paths are relative to the file being checked."
   7967   :type '(repeat (file :tag "Include file"))
   7968   :safe #'flycheck-string-list-p
   7969   :package-version '(flycheck . "0.20"))
   7970 
   7971 (flycheck-def-option-var flycheck-gcc-language-standard nil c/c++-gcc
   7972   "The language standard to use in GCC.
   7973 
   7974 The value of this variable is either a string denoting a language
   7975 standard, or nil, to use the default standard.  When non-nil,
   7976 pass the language standard via the `-std' option."
   7977   :type '(choice (const :tag "Default standard" nil)
   7978                  (string :tag "Language standard"))
   7979   :safe #'flycheck-string-or-nil-p
   7980   :package-version '(flycheck . "0.20"))
   7981 (make-variable-buffer-local 'flycheck-gcc-language-standard)
   7982 
   7983 (flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc
   7984   "Whether to disable exceptions in GCC.
   7985 
   7986 When non-nil, disable exceptions for syntax checks, via
   7987 `-fno-exceptions'."
   7988   :type 'boolean
   7989   :safe #'booleanp
   7990   :package-version '(flycheck . "0.20"))
   7991 
   7992 (flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc
   7993   "Whether to disable RTTI in GCC.
   7994 
   7995 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
   7996   :type 'boolean
   7997   :safe #'booleanp
   7998   :package-version '(flycheck . "0.20"))
   7999 
   8000 (flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc
   8001   "Whether to enable OpenMP in GCC.
   8002 
   8003 When non-nil, enable OpenMP for syntax checkers, via
   8004 `-fopenmp'."
   8005   :type 'boolean
   8006   :safe #'booleanp
   8007   :package-version '(flycheck . "0.21"))
   8008 
   8009 (flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc
   8010   "Whether to warn about language extensions in GCC.
   8011 
   8012 For ISO C, follows the version specified by any -std option used.
   8013 When non-nil, disable non-ISO extensions to C/C++ via
   8014 `-pedantic'."
   8015   :type 'boolean
   8016   :safe #'booleanp
   8017   :package-version '(flycheck . "0.23"))
   8018 
   8019 (flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc
   8020   "Whether to error on language extensions in GCC.
   8021 
   8022 For ISO C, follows the version specified by any -std option used.
   8023 When non-nil, disable non-ISO extensions to C/C++ via
   8024 `-pedantic-errors'."
   8025   :type 'boolean
   8026   :safe #'booleanp
   8027   :package-version '(flycheck . "0.23"))
   8028 
   8029 (flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc
   8030   "A list of additional warnings to enable in GCC.
   8031 
   8032 The value of this variable is a list of strings, where each string
   8033 is the name of a warning category to enable.  By default, all
   8034 recommended warnings and some extra warnings are enabled (as by
   8035 `-Wall' and `-Wextra' respectively).
   8036 
   8037 Refer to the gcc manual at URL
   8038 `https://gcc.gnu.org/onlinedocs/gcc/' for more information about
   8039 warnings."
   8040   :type '(choice (const :tag "No additional warnings" nil)
   8041                  (repeat :tag "Additional warnings"
   8042                          (string :tag "Warning name")))
   8043   :safe #'flycheck-string-list-p
   8044   :package-version '(flycheck . "0.20"))
   8045 
   8046 (flycheck-define-checker c/c++-gcc
   8047   "A C/C++ syntax checker using GCC.
   8048 
   8049 Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
   8050   :command ("gcc"
   8051             "-fshow-column"
   8052             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   8053             (option "-std=" flycheck-gcc-language-standard concat)
   8054             (option-flag "-pedantic" flycheck-gcc-pedantic)
   8055             (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors)
   8056             (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions)
   8057             (option-flag "-fno-rtti" flycheck-gcc-no-rtti)
   8058             (option-flag "-fopenmp" flycheck-gcc-openmp)
   8059             (option-list "-include" flycheck-gcc-includes)
   8060             (option-list "-W" flycheck-gcc-warnings concat)
   8061             (option-list "-D" flycheck-gcc-definitions concat)
   8062             (option-list "-I" flycheck-gcc-include-path)
   8063             (eval flycheck-gcc-args)
   8064             "-x" (eval
   8065                   (pcase major-mode
   8066                     ((or `c++-mode `c++-ts-mode) "c++")
   8067                     ((or `c-mode `c-ts-mode) "c")))
   8068             ;; GCC performs full checking only when actually compiling, so
   8069             ;; `-fsyntax-only' is not enough. Just let it generate assembly
   8070             ;; code.
   8071             "-S" "-o" null-device
   8072             ;; Read from standard input
   8073             "-")
   8074   :standard-input t
   8075   :error-patterns
   8076   ((info line-start (or "<stdin>" (file-name))
   8077          ":" line (optional ":" column)
   8078          ": note: " (message) line-end)
   8079    (warning line-start (or "<stdin>" (file-name))
   8080             ":" line (optional ":" column)
   8081             ": warning: " (message (one-or-more (not (any "\n["))))
   8082             (optional "[" (id (one-or-more not-newline)) "]") line-end)
   8083    (error line-start (or "<stdin>" (file-name))
   8084           ":" line (optional ":" column)
   8085           ": " (or "fatal error" "error") ": " (message) line-end))
   8086   :modes (c-mode c++-mode c-ts-mode c++-ts-mode)
   8087   :next-checkers ((warning . c/c++-cppcheck)))
   8088 
   8089 (flycheck-def-option-var flycheck-cppcheck-checks '("style") c/c++-cppcheck
   8090   "Enabled checks for Cppcheck.
   8091 
   8092 The value of this variable is a list of strings, where each
   8093 string is the name of an additional check to enable.  By default,
   8094 all coding style checks are enabled.
   8095 
   8096 See section \"Enable message\" in the Cppcheck manual at URL
   8097 `https://cppcheck.sourceforge.net/manual.pdf', and the
   8098 documentation of the `--enable' option for more information,
   8099 including a list of supported checks."
   8100   :type '(repeat :tag "Additional checks"
   8101                  (string :tag "Check name"))
   8102   :safe #'flycheck-string-list-p
   8103   :package-version '(flycheck . "0.14"))
   8104 
   8105 (flycheck-def-option-var flycheck-cppcheck-standards nil c/c++-cppcheck
   8106   "The standards to use in cppcheck.
   8107 
   8108 The value of this variable is either a list of strings denoting
   8109 the standards to use, or nil to pass nothing to cppcheck.  When
   8110 non-nil, pass the standards via one or more `--std=' options."
   8111   :type '(choice (const :tag "Default" nil)
   8112                  (repeat :tag "Custom standards"
   8113                          (string :tag "Standard name")))
   8114   :safe #'flycheck-string-list-p
   8115   :package-version '(flycheck . "28"))
   8116 (make-variable-buffer-local 'flycheck-cppcheck-standards)
   8117 
   8118 (flycheck-def-option-var flycheck-cppcheck-suppressions-file nil c/c++-cppcheck
   8119   "The suppressions file to use in cppcheck.
   8120 
   8121 The value of this variable is a file with the suppressions to
   8122 use, or nil to pass nothing to cppcheck.  When non-nil, pass the
   8123 suppressions file via the `--suppressions-list=' option."
   8124   :type '(choice (const :tag "Default" nil)
   8125                  (file :tag "Suppressions file"))
   8126   :safe #'flycheck-string-or-nil-p
   8127   :package-version '(flycheck . "32"))
   8128 (make-variable-buffer-local 'flycheck-cppcheck-suppressions-file)
   8129 
   8130 (flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck
   8131   "The suppressions to use in cppcheck.
   8132 
   8133 The value of this variable is either a list of strings denoting
   8134 the suppressions to use, or nil to pass nothing to cppcheck.
   8135 When non-nil, pass the suppressions via one or more `--suppress='
   8136 options."
   8137   :type '(choice (const :tag "Default" nil)
   8138                  (repeat :tag "Additional suppressions"
   8139                          (string :tag "Suppression")))
   8140   :safe #'flycheck-string-list-p
   8141   :package-version '(flycheck . "28"))
   8142 
   8143 (flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck
   8144   "Whether to enable Cppcheck inconclusive checks.
   8145 
   8146 When non-nil, enable Cppcheck inconclusive checks.  This allows Cppcheck to
   8147 report warnings it's not certain of, but it may result in false positives.
   8148 
   8149 This will have no effect when using Cppcheck 1.53 and older."
   8150   :type 'boolean
   8151   :safe #'booleanp
   8152   :package-version '(flycheck . "0.19"))
   8153 
   8154 (flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck
   8155   "A list of include directories for cppcheck.
   8156 
   8157 The value of this variable is a list of strings, where each
   8158 string is a directory to add to the include path of cppcheck.
   8159 Relative paths are relative to the file being checked."
   8160   :type '(repeat (directory :tag "Include directory"))
   8161   :safe #'flycheck-string-list-p
   8162   :package-version '(flycheck . "0.24"))
   8163 
   8164 (flycheck-define-checker c/c++-cppcheck
   8165   "A C/C++ checker using cppcheck.
   8166 
   8167 See URL `https://cppcheck.sourceforge.net/'."
   8168   :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr"
   8169             (option "--enable=" flycheck-cppcheck-checks concat
   8170                     flycheck-option-comma-separated-list)
   8171             (option-flag "--inconclusive" flycheck-cppcheck-inconclusive)
   8172             (option-list "-I" flycheck-cppcheck-include-path)
   8173             (option-list "--std=" flycheck-cppcheck-standards concat)
   8174             (option-list "--suppress=" flycheck-cppcheck-suppressions concat)
   8175             (option "--suppressions-list="
   8176                     flycheck-cppcheck-suppressions-file concat)
   8177             "-x" (eval
   8178                   (pcase major-mode
   8179                     ((or `c++-mode `c++-ts-mode) "c++")
   8180                     ((or `c-mode `c-ts-mode) "c")))
   8181             source)
   8182   :error-parser flycheck-parse-cppcheck
   8183   :modes (c-mode c++-mode c-ts-mode c++-ts-mode))
   8184 
   8185 (flycheck-define-checker cfengine
   8186   "A CFEngine syntax checker using cf-promises.
   8187 
   8188 See URL `https://cfengine.com/'."
   8189   :command ("cf-promises" "-Wall" "-f"
   8190             ;; We must stay in the same directory to resolve @include
   8191             source-inplace)
   8192   :error-patterns
   8193   ((warning line-start (file-name) ":" line ":" column
   8194             ": warning: " (message) line-end)
   8195    (error line-start (file-name) ":" line ":" column
   8196           ": error: " (message) line-end))
   8197   :modes (cfengine-mode cfengine3-mode))
   8198 
   8199 (flycheck-define-checker coffee
   8200   "A CoffeeScript syntax checker using coffee.
   8201 
   8202 See URL `https://coffeescript.org/'."
   8203   ;; --print suppresses generation of compiled .js files
   8204   :command ("coffee" "--compile" "--print" "--stdio")
   8205   :standard-input t
   8206   :error-patterns
   8207   ((error line-start "[stdin]:" line ":" column
   8208           ": error: " (message) line-end))
   8209   :modes coffee-mode
   8210   :next-checkers ((warning . coffee-coffeelint)))
   8211 
   8212 (flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint
   8213                               ".coffeelint.json")
   8214 
   8215 (flycheck-define-checker coffee-coffeelint
   8216   "A CoffeeScript style checker using coffeelint.
   8217 
   8218 See URL `https://www.coffeelint.org/'."
   8219   :command
   8220   ("coffeelint"
   8221    (config-file "--file" flycheck-coffeelintrc)
   8222    "--stdin" "--reporter" "checkstyle")
   8223   :standard-input t
   8224   :error-parser flycheck-parse-checkstyle
   8225   :error-filter (lambda (errors)
   8226                   (flycheck-remove-error-file-names
   8227                    "stdin" (flycheck-remove-error-ids
   8228                             (flycheck-sanitize-errors errors))))
   8229   :modes coffee-mode)
   8230 
   8231 (flycheck-define-checker css-csslint
   8232   "A CSS syntax and style checker using csslint.
   8233 
   8234 See URL `https://github.com/CSSLint/csslint'."
   8235   :command ("csslint" "--format=checkstyle-xml" source)
   8236   :error-parser flycheck-parse-checkstyle
   8237   :error-filter flycheck-dequalify-error-ids
   8238   :modes (css-mode css-ts-mode))
   8239 
   8240 (defconst flycheck-stylelint-args '("--formatter" "json")
   8241   "Common arguments to stylelint invocations.")
   8242 
   8243 ;; Limit the length of the generated docstring by including only the first three
   8244 ;; checker symbols, otherwise emacs will complain about the docstring length
   8245 ;; and may refuse to compile the package.
   8246 (let ((print-length 3))
   8247   (flycheck-def-config-file-var flycheck-stylelintrc
   8248       (css-stylelint scss-stylelint sass-stylelint less-stylelint) nil))
   8249 
   8250 (flycheck-def-option-var flycheck-stylelint-quiet
   8251     nil (css-stylelint scss-stylelint sass-stylelint less-stylelint)
   8252   "Whether to run stylelint in quiet mode.
   8253 
   8254 When non-nil, enable quiet mode, via `--quiet'."
   8255   :type 'boolean
   8256   :safe #'booleanp
   8257   :package-version '(flycheck . 26))
   8258 
   8259 (defconst flycheck-stylelint-error-re
   8260   (flycheck-rx-to-string
   8261    '(: line-start (id (one-or-more word)) ": " (message) line-end)))
   8262 
   8263 (defun flycheck-parse-stylelint (output checker buffer)
   8264   "Parse stylelint errors from OUTPUT.
   8265 
   8266 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   8267 the BUFFER that was checked respectively.
   8268 
   8269 The CHECKER usually returns the errors as JSON.
   8270 
   8271 If the CHECKER throws an Error it returns an Error message with a stacktrace."
   8272   (condition-case nil
   8273       (flycheck-parse-stylelint-json output checker buffer)
   8274 
   8275     ;; The output could not be parsed as JSON
   8276     (json-error
   8277 
   8278      ;; Extract a flycheck error from the output (with a regular expression)
   8279      ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id
   8280      (when (string-match flycheck-stylelint-error-re output)
   8281        (list (flycheck-error-new-at
   8282               1 nil 'error
   8283               (match-string 4 output)
   8284               :id (match-string 5 output)
   8285               :checker checker
   8286               :buffer buffer
   8287               :filename (buffer-file-name buffer)))))))
   8288 
   8289 (defun flycheck-parse-stylelint-json (output checker buffer)
   8290   "Parse stylelint JSON errors from OUTPUT.
   8291 
   8292 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   8293 the BUFFER that was checked respectively.
   8294 
   8295 See URL `https://stylelint.io/developer-guide/formatters/' for information
   8296 about the JSON format of stylelint."
   8297   (let ((json-object-type 'plist))
   8298 
   8299     ;; stylelint returns a vector of result objects
   8300     ;; Since we only passed one file, the first element is enough
   8301     (let* ((stylelint-output (elt (json-read-from-string output) 0))
   8302            (filename (buffer-file-name buffer))
   8303 
   8304            ;; Turn all deprecations into warnings
   8305            (deprecations
   8306             (mapcar (lambda (d)
   8307                       (flycheck-error-new-at
   8308                        1 nil 'warning
   8309                        (plist-get d :text)
   8310                        :id "Deprecation Warning"
   8311                        :checker checker
   8312                        :buffer buffer
   8313                        :filename filename))
   8314                     (plist-get stylelint-output :deprecations)))
   8315 
   8316            ;; Turn all invalid options into errors
   8317            (invalid-options
   8318             (mapcar (lambda (io)
   8319                       (flycheck-error-new-at
   8320                        1 nil 'error
   8321                        (plist-get io :text)
   8322                        :id "Invalid Option"
   8323                        :checker checker
   8324                        :buffer buffer
   8325                        :filename filename))
   8326                     (plist-get stylelint-output :invalidOptionWarnings)))
   8327 
   8328            ;; Read all linting warnings
   8329            (warnings
   8330             (mapcar (lambda (w)
   8331                       (flycheck-error-new-at
   8332                        (plist-get w :line) (plist-get w :column)
   8333                        (pcase (plist-get w :severity)
   8334                          (`"error"   'error)
   8335                          (`"warning" 'warning)
   8336                          ;; Default to info for unknown .severity
   8337                          (_          'info))
   8338                        (plist-get w :text)
   8339                        :id (plist-get w :rule)
   8340                        :checker checker
   8341                        :buffer buffer
   8342                        :filename filename))
   8343                     (plist-get stylelint-output :warnings))))
   8344 
   8345       ;; Return the combined errors (deprecations, invalid options, warnings)
   8346       (append deprecations invalid-options warnings))))
   8347 
   8348 (defun flycheck--stylelint-config-exists-p (checker)
   8349   "Whether there is a valid stylelint CHECKER config for the current buffer."
   8350   (eql 0 (flycheck-call-checker-process
   8351           checker nil nil nil
   8352           "--print-config" (or buffer-file-name "index.js"))))
   8353 
   8354 (defun flycheck--stylelint-get-major-version (checker)
   8355   "Return major version of stylelint CHECKER."
   8356   (let ((cb (current-buffer)))
   8357     (with-temp-buffer
   8358       (let ((temp-buffer (current-buffer)))
   8359         (with-current-buffer cb
   8360           (flycheck-call-checker-process
   8361            checker nil temp-buffer nil "--version"))
   8362         (string-to-number (car (split-string (buffer-string) "\\.")))))))
   8363 
   8364 (defun flycheck--stylelint-verify (checker)
   8365   "Verify stylelint setup for CHECKER."
   8366   (let ((have-config (flycheck--stylelint-config-exists-p checker)))
   8367     (list
   8368      (flycheck-verification-result-new
   8369       :label "configuration available"
   8370       :message (if have-config "yes" "no config file found")
   8371       :face (if have-config 'success '(bold error)))
   8372      (flycheck-verification-result-new
   8373       :label "stylecheck version"
   8374       :message (number-to-string (flycheck--stylelint-get-major-version checker))
   8375       :face 'success))))
   8376 
   8377 (flycheck-define-checker css-stylelint
   8378   "A CSS syntax and style checker using stylelint.
   8379 
   8380 See URL `https://stylelint.io/'."
   8381   :command ("stylelint"
   8382             (eval flycheck-stylelint-args)
   8383             (option-flag "--quiet" flycheck-stylelint-quiet)
   8384             (config-file "--config" flycheck-stylelintrc)
   8385             "--stdin-filename" (eval (or (buffer-file-name) "style.css")))
   8386   :standard-input t
   8387   :verify (lambda (_) (flycheck--stylelint-verify 'css-stylelint))
   8388   :error-parser flycheck-parse-stylelint
   8389   :predicate flycheck-buffer-nonempty-p
   8390   :modes (css-mode css-ts-mode)
   8391   :error-explainer
   8392   (lambda (err)
   8393     (let ((error-code (flycheck-error-id err))
   8394           (url "https://stylelint.io/user-guide/rules/%s"))
   8395       (and error-code `(url . ,(format url error-code))))))
   8396 
   8397 (flycheck-def-option-var flycheck-cuda-language-standard nil cuda-nvcc
   8398   "Our CUDA Language Standard."
   8399   :type '(choice (const :tag "Default standard" nil)
   8400                  (string :tag "Language standard"))
   8401   :safe #'flycheck-string-or-nil-p
   8402   :package-version '(flycheck . "32"))
   8403 (make-variable-buffer-local 'flycheck-cuda-language-standard)
   8404 
   8405 (flycheck-def-option-var flycheck-cuda-gencodes nil cuda-nvcc
   8406   "Our real and virtual GPU architectures to pass to nvcc."
   8407   :type '(repeat (file :tag "GPU architecture"))
   8408   :safe #'flycheck-string-list-p
   8409   :package-version '(flycheck . "32"))
   8410 
   8411 (flycheck-def-option-var flycheck-cuda-includes nil cuda-nvcc
   8412   "Our include directories to pass to nvcc."
   8413   :type '(repeat (file :tag "Include file"))
   8414   :safe #'flycheck-string-list-p
   8415   :package-version '(flycheck . "32"))
   8416 
   8417 (flycheck-def-option-var flycheck-cuda-definitions nil cuda-nvcc
   8418   "Additional preprocessor definitions for nvcc.
   8419 A list of strings to pass to cuda, a la flycheck-clang"
   8420   :type '(repeat (string :tag "Definitions"))
   8421   :safe #'flycheck-string-list-p
   8422   :package-version '(flycheck . "32"))
   8423 
   8424 (flycheck-def-option-var flycheck-cuda-include-path nil cuda-nvcc
   8425   "A list of include directories for nvcc."
   8426   :type '(repeat (directory :tag "Include directory"))
   8427   :safe #'flycheck-string-list-p
   8428   :package-version '(flycheck . "32"))
   8429 
   8430 (flycheck-def-option-var flycheck-cuda-relaxed-constexpr nil cuda-nvcc
   8431   "Enable calling host constexpr from device function for nvcc.
   8432 
   8433 When non-nil, enable experimental calling of a constexpr __host__
   8434 function from a __device__ function."
   8435   :type 'boolean
   8436   :safe #'booleanp
   8437   :package-version '(flycheck . "35"))
   8438 
   8439 (flycheck-def-option-var flycheck-cuda-extended-lambda nil cuda-nvcc
   8440   "Enable annotating lambda functions with __host__ or __device__.
   8441 
   8442 When non-nil, enable experimental compilation of __host__ and
   8443 __device__ lambda functions."
   8444   :type 'boolean
   8445   :safe #'booleanp
   8446   :package-version '(flycheck . "35"))
   8447 
   8448 (flycheck-define-checker cuda-nvcc
   8449   "A CUDA C/C++ syntax checker using nvcc.
   8450 
   8451 See URL `https://developer.nvidia.com/cuda-llvm-compiler'."
   8452   :command ("nvcc"
   8453             "-c" ;; Compile Only
   8454             "--output-file" "/dev/null" ;; avoid creating output .o
   8455             "--x=cu" ;; explicitly specify it's a CUDA language file
   8456             "-rdc=true" ;; Allow linking with external cuda funcions
   8457             (option "-std=" flycheck-cuda-language-standard concat)
   8458             (option-flag "--expt-relaxed-constexpr" flycheck-cuda-relaxed-constexpr)
   8459             (option-flag "--expt-extended-lambda" flycheck-cuda-extended-lambda)
   8460             (option-list "-include" flycheck-cuda-includes)
   8461             (option-list "-gencode" flycheck-cuda-gencodes)
   8462             (option-list "-D" flycheck-cuda-definitions concat)
   8463             (option-list "-I" flycheck-cuda-include-path)
   8464             source)
   8465   :error-patterns
   8466   ((error line-start
   8467           (message "In file included from")
   8468           " " (or "<stdin>" (file-name))
   8469           ":" line ":" line-end)
   8470    (error line-start (or "<stdin>" (file-name))
   8471           "(" line "): error: " (message) line-end)
   8472    (error line-start (or "<stdin>" (file-name))
   8473           ":" line ":" column
   8474           ": fatal error: " (optional (message)) line-end)
   8475    (warning line-start (or "<stdin>" (file-name))
   8476             "(" line "): warning: " (message) line-end))
   8477   :modes cuda-mode)
   8478 
   8479 
   8480 (flycheck-def-option-var flycheck-cwl-schema-path nil cwl
   8481   "A path for the schema file for Common Workflow Language.
   8482 
   8483 The value of this variable is a string that denotes a path for
   8484 the schema file of Common Workflow Language."
   8485   :type '(choice (const :tag "None" nil)
   8486                  (file :tag "Schema file"))
   8487   :safe #'flycheck-string-or-nil-p)
   8488 
   8489 (flycheck-define-checker cwl
   8490   "A CWL syntax checker using Schema Salad validator.
   8491 
   8492 Requires Schema Salad 2.6.20171101113912 or newer.
   8493 See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'."
   8494   :command ("schema-salad-tool"
   8495             "--quiet"
   8496             "--print-oneline"
   8497             (eval flycheck-cwl-schema-path)
   8498             source-inplace)
   8499   :error-patterns
   8500   ((error line-start
   8501           (file-name) ":" line ":" column ":" (zero-or-more blank)
   8502           (message (one-or-more not-newline))
   8503           line-end))
   8504   :modes cwl-mode)
   8505 
   8506 (defconst flycheck-d-module-re
   8507   (rx "module" (one-or-more (syntax whitespace))
   8508       (group (one-or-more (not (syntax whitespace))))
   8509       (zero-or-more (syntax whitespace))
   8510       ";")
   8511   "Regular expression to match a D module declaration.")
   8512 
   8513 (defun flycheck-d-base-directory ()
   8514   "Get the relative base directory path for this module."
   8515   (let* ((file-name (buffer-file-name))
   8516          (module-file (if (and file-name
   8517                                (string= (file-name-nondirectory file-name)
   8518                                         "package.d"))
   8519                           (directory-file-name (file-name-directory file-name))
   8520                         file-name)))
   8521     (flycheck-module-root-directory
   8522      (flycheck-find-in-buffer flycheck-d-module-re)
   8523      module-file)))
   8524 
   8525 (flycheck-def-option-var flycheck-dmd-include-path nil d-dmd
   8526   "A list of include directories for dmd.
   8527 
   8528 The value of this variable is a list of strings, where each
   8529 string is a directory to add to the include path of dmd.
   8530 Relative paths are relative to the file being checked."
   8531   :type '(repeat (directory :tag "Include directory"))
   8532   :safe #'flycheck-string-list-p
   8533   :package-version '(flycheck . "0.18"))
   8534 
   8535 (flycheck-def-args-var flycheck-dmd-args d-dmd
   8536   :package-version '(flycheck . "0.24"))
   8537 
   8538 (flycheck-define-checker d-dmd
   8539   "A D syntax checker using the DMD compiler.
   8540 
   8541 Requires DMD 2.066 or newer.  See URL `https://dlang.org/'."
   8542   :command ("dmd"
   8543             "-debug"                    ; Compile in debug mode
   8544             "-o-"                       ; Don't generate an object file
   8545             "-vcolumns"                 ; Add columns in output
   8546             "-wi" ; Compilation will continue even if there are warnings
   8547             (eval (concat "-I" (flycheck-d-base-directory)))
   8548             (option-list "-I" flycheck-dmd-include-path concat)
   8549             (eval flycheck-dmd-args)
   8550             (source ".d"))
   8551   :error-patterns
   8552   ((error line-start
   8553           (file-name) "(" line "," column "): Error: " (message)
   8554           line-end)
   8555    (warning line-start (file-name) "(" line "," column "): "
   8556             (or "Warning" "Deprecation") ": " (message) line-end)
   8557    (info line-start (file-name) "(" line "," column "): "
   8558          (one-or-more " ") (message) line-end))
   8559   :modes d-mode)
   8560 
   8561 (flycheck-define-checker dockerfile-hadolint
   8562   "A Dockerfile syntax checker using the hadolint.
   8563 
   8564 See URL `https://github.com/hadolint/hadolint/'."
   8565   :command ("hadolint" "--no-color" "-")
   8566   :standard-input t
   8567   :error-patterns
   8568   ((error line-start
   8569           (file-name) ":" line " " (id (one-or-more alnum)) " error: " (message)
   8570           line-end)
   8571    (warning line-start
   8572             (file-name) ":" line " " (id (one-or-more alnum))
   8573             " warning: " (message) line-end)
   8574    (info line-start
   8575          (file-name) ":" line " " (id (one-or-more alnum)) " info: " (message)
   8576          line-end)
   8577    (error line-start
   8578           (file-name) ":" line ":" column " " (message)
   8579           line-end))
   8580   :error-filter
   8581   (lambda (errors)
   8582     (flycheck-sanitize-errors
   8583      (flycheck-remove-error-file-names "-" errors)))
   8584   :modes (dockerfile-mode dockerfile-ts-mode))
   8585 
   8586 (defun flycheck-credo--working-directory (&rest _ignored)
   8587   "Check if `credo' is installed as dependency in the application."
   8588   (and buffer-file-name
   8589        (locate-dominating-file buffer-file-name "deps/credo")))
   8590 
   8591 (flycheck-def-option-var flycheck-elixir-credo-strict nil elixir-credo
   8592   "Enable strict mode in `credo'.
   8593 
   8594 When non-nil, pass the `--strict' flag to credo."
   8595   :type 'boolean
   8596   :safe #'booleanp
   8597   :package-version '(flycheck . "32"))
   8598 
   8599 (flycheck-define-checker elixir-credo
   8600   "An Elixir checker for static code analysis using Credo.
   8601 
   8602 See `https://credo-ci.org/'."
   8603   :command ("mix" "credo"
   8604             (option-flag "--strict" flycheck-elixir-credo-strict)
   8605             "--format" "flycheck"
   8606             "--read-from-stdin" source-original)
   8607   :standard-input t
   8608   :working-directory flycheck-credo--working-directory
   8609   :enabled flycheck-credo--working-directory
   8610   :error-patterns
   8611   ((info line-start
   8612          (file-name) ":" line (optional ":" column) ": "
   8613          (or "F" "R" "C")  ": " (message) line-end)
   8614    (warning line-start
   8615             (file-name) ":" line (optional ":" column) ": "
   8616             (or "D" "W")  ": " (message) line-end))
   8617   :modes elixir-mode)
   8618 
   8619 (defconst flycheck-this-emacs-executable
   8620   (concat invocation-directory invocation-name)
   8621   "The path to the currently running Emacs executable.")
   8622 
   8623 (defconst flycheck-emacs-args '("-Q" "--batch")
   8624   "Common arguments to Emacs invocations.")
   8625 
   8626 (defmacro flycheck-prepare-emacs-lisp-form (&rest body)
   8627   "Prepare BODY for use as check form in a subprocess."
   8628   (declare (indent 0))
   8629   `(flycheck-sexp-to-string
   8630     '(progn
   8631        (defvar jka-compr-inhibit)
   8632        (unwind-protect
   8633            ;; Flycheck inhibits compression of temporary files, thus we
   8634            ;; must not attempt to decompress.
   8635            (let ((jka-compr-inhibit t))
   8636              ;; Strip option-argument separator from arguments, if present
   8637              (when (equal (car command-line-args-left) "--")
   8638                (setq command-line-args-left (cdr command-line-args-left)))
   8639              ,@body)
   8640          ;; Prevent Emacs from processing the arguments on its own, see
   8641          ;; https://github.com/flycheck/flycheck/issues/319
   8642          (setq command-line-args-left nil)))))
   8643 
   8644 (defun flycheck-emacs-lisp-bytecomp-config-form ()
   8645   "Prepare an Emacs Lisp form to set byte-compiler variables."
   8646   (flycheck-sexp-to-string
   8647    `(progn
   8648       (require 'bytecomp)
   8649       (setq byte-compile-root-dir
   8650             ,(if buffer-file-name
   8651                  (file-name-directory buffer-file-name)
   8652                default-directory)))))
   8653 
   8654 (defconst flycheck-emacs-lisp-check-form
   8655   (flycheck-prepare-emacs-lisp-form
   8656     ;; Keep track of the generated bytecode files, to delete them after byte
   8657     ;; compilation.
   8658     (require 'bytecomp)
   8659     (defvar flycheck-byte-compiled-files nil)
   8660     (let ((byte-compile-dest-file-function
   8661            (lambda (source)
   8662              (let ((temp-file (make-temp-file (file-name-nondirectory source))))
   8663                (push temp-file flycheck-byte-compiled-files)
   8664                temp-file))))
   8665       (unwind-protect
   8666           (byte-compile-file (car command-line-args-left))
   8667         (mapc (lambda (f) (ignore-errors (delete-file f)))
   8668               flycheck-byte-compiled-files))
   8669       (when (bound-and-true-p flycheck-emacs-lisp-check-declare)
   8670         (check-declare-file (car command-line-args-left))))))
   8671 
   8672 (flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp
   8673   "Load path to use in the Emacs Lisp syntax checker.
   8674 
   8675 When set to `inherit', use the `load-path' of the current Emacs
   8676 session during syntax checking.
   8677 
   8678 When set to a list of strings, add each directory in this list to
   8679 the `load-path' before invoking the byte compiler.  Relative
   8680 paths in this list are expanded against the `default-directory'
   8681 of the buffer to check.
   8682 
   8683 When nil, do not explicitly set the `load-path' during syntax
   8684 checking.  The syntax check only uses the built-in `load-path' of
   8685 Emacs in this case.
   8686 
   8687 Note that changing this variable can lead to wrong results of the
   8688 syntax check, e.g. if an unexpected version of a required library
   8689 is used."
   8690   :type '(choice (const :tag "Inherit current `load-path'" inherit)
   8691                  (repeat :tag "Load path" directory))
   8692   :risky t
   8693   :package-version '(flycheck . "0.14"))
   8694 
   8695 (flycheck-def-option-var flycheck-emacs-lisp-initialize-packages
   8696     'auto emacs-lisp
   8697   "Whether to initialize packages in the Emacs Lisp syntax checker.
   8698 
   8699 When nil, never initialize packages.  When `auto', initialize
   8700 packages only when checking `user-init-file' or files from
   8701 `user-emacs-directory'.  For any other non-nil value, always
   8702 initialize packages.
   8703 
   8704 When initializing packages is enabled the `emacs-lisp' syntax
   8705 checker calls `package-initialize' before byte-compiling the file
   8706 to be checked.  It also sets `package-user-dir' according to
   8707 `flycheck-emacs-lisp-package-user-dir'."
   8708   :type '(choice (const :tag "Do not initialize packages" nil)
   8709                  (const :tag "Initialize packages for configuration only" auto)
   8710                  (const :tag "Always initialize packages" t))
   8711   :risky t
   8712   :package-version '(flycheck . "0.14"))
   8713 
   8714 (defconst flycheck-emacs-lisp-package-initialize-form
   8715   (flycheck-sexp-to-string
   8716    '(with-demoted-errors "Error during package initialization: %S"
   8717       (package-initialize)))
   8718   "Form used to initialize packages.")
   8719 
   8720 (defun flycheck-option-emacs-lisp-package-initialize (value)
   8721   "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'."
   8722   (let ((shall-initialize
   8723          (if (eq value 'auto)
   8724              (or (flycheck-in-user-emacs-directory-p
   8725                   (or buffer-file-name default-directory))
   8726                  ;; `user-init-file' is nil in non-interactive sessions.  Now,
   8727                  ;; no user would possibly use Flycheck in a non-interactive
   8728                  ;; session, but our unit tests run non-interactively, so we
   8729                  ;; have to handle this case anyway
   8730                  (and user-init-file buffer-file-name
   8731                       (flycheck-same-files-p buffer-file-name user-init-file)))
   8732            value)))
   8733     (when shall-initialize
   8734       ;; If packages shall be initialized, return the corresponding form,
   8735       ;; otherwise make Flycheck ignore the option by returning nil.
   8736       flycheck-emacs-lisp-package-initialize-form)))
   8737 
   8738 (flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp
   8739   "Package directory for the Emacs Lisp syntax checker.
   8740 
   8741 If set to a string set `package-user-dir' to the value of this
   8742 variable before initializing packages. If set to nil just inherit
   8743 the value of `package-user-dir' from the running Emacs session.
   8744 
   8745 This variable has no effect, if
   8746 `flycheck-emacs-lisp-initialize-packages' is nil."
   8747   :type '(choice (const :tag "Default package directory" nil)
   8748                  (directory :tag "Custom package directory"))
   8749   :risky t
   8750   :package-version '(flycheck . "0.14"))
   8751 
   8752 (defun flycheck-option-emacs-lisp-package-user-dir (value)
   8753   "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'."
   8754   ;; Inherit the package directory from our Emacs session
   8755   (let ((value (or value (bound-and-true-p package-user-dir))))
   8756     (when value
   8757       (flycheck-sexp-to-string `(setq package-user-dir ,value)))))
   8758 
   8759 (flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp
   8760   "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’."
   8761   :type '(choice (const :tag "Do not check declare forms" nil)
   8762                  (const :tag "Check declare forms" t))
   8763   :risky t
   8764   :package-version '(flycheck . "31"))
   8765 
   8766 (defun flycheck-option-emacs-lisp-check-declare (value)
   8767   "Option VALUE filter for `flycheck-emacs-lisp-check-declare'."
   8768   (when value
   8769     (flycheck-sexp-to-string
   8770      `(progn
   8771         (defvar flycheck-emacs-lisp-check-declare)
   8772         (setq flycheck-emacs-lisp-check-declare ,value)))))
   8773 
   8774 (defun flycheck--emacs-lisp-enabled-p ()
   8775   "Check whether to enable Emacs Lisp checker in the current buffer."
   8776   (not
   8777    (or
   8778     ;; Do not check buffers used for autoloads generation during package
   8779     ;; installation.  These buffers are too short-lived for being checked, and
   8780     ;; doing so causes spurious errors.  See
   8781     ;; https://github.com/flycheck/flycheck/issues/45 and
   8782     ;; https://github.com/bbatsov/prelude/issues/248.  We must also not check
   8783     ;; compilation buffers, but as these are ephemeral, Flycheck won't check
   8784     ;; them anyway.
   8785     (flycheck-autoloads-file-p)
   8786     ;; Cask/Carton and dir-locals files contain data, not code, and don't need
   8787     ;; to follow Checkdoc conventions either.
   8788     (and (buffer-file-name)
   8789          (member (file-name-nondirectory (buffer-file-name))
   8790                  '("Cask" "Carton" ".dir-locals.el" ".dir-locals-2.el"))))))
   8791 
   8792 (defun flycheck--emacs-lisp-checkdoc-enabled-p ()
   8793   "Check whether to enable Emacs Lisp Checkdoc in the current buffer."
   8794   (and (flycheck--emacs-lisp-enabled-p)
   8795        ;; These files are valid Lisp, but don't contain "standard" comments.
   8796        (not (member (buffer-file-name) '("Eldev" "Eldev-local")))))
   8797 
   8798 (flycheck-define-checker emacs-lisp
   8799   "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler.
   8800 
   8801 See Info Node `(elisp)Byte Compilation'."
   8802   :command ("emacs" (eval flycheck-emacs-args)
   8803             (eval
   8804              (let ((path (pcase flycheck-emacs-lisp-load-path
   8805                            (`inherit load-path)
   8806                            (p (seq-map #'expand-file-name p)))))
   8807                (flycheck-prepend-with-option "--directory" path)))
   8808             (option "--eval" flycheck-emacs-lisp-package-user-dir nil
   8809                     flycheck-option-emacs-lisp-package-user-dir)
   8810             (option "--eval" flycheck-emacs-lisp-initialize-packages nil
   8811                     flycheck-option-emacs-lisp-package-initialize)
   8812             (option "--eval" flycheck-emacs-lisp-check-declare nil
   8813                     flycheck-option-emacs-lisp-check-declare)
   8814             "--eval" (eval (flycheck-emacs-lisp-bytecomp-config-form))
   8815             "--eval" (eval flycheck-emacs-lisp-check-form)
   8816             "--"
   8817             source-inplace)
   8818   :error-patterns
   8819   ((error line-start (file-name) ":" line ":" column ":"
   8820           (zero-or-more whitespace) "Error:" (zero-or-more whitespace)
   8821           (message (zero-or-more not-newline)
   8822                    (zero-or-more "\n    " (zero-or-more not-newline)))
   8823           line-end)
   8824    (warning line-start (file-name) ":" line ":" column ":"
   8825             (zero-or-more whitespace) "Warning:" (zero-or-more whitespace)
   8826             (message (zero-or-more not-newline)
   8827                      (zero-or-more "\n    " (zero-or-more not-newline)))
   8828             line-end)
   8829    (warning line-start (file-name) ":" line (optional ":" column) ":"
   8830             (zero-or-more whitespace) "Warning (check-declare): said\n"
   8831             (message (zero-or-more "    " (zero-or-more not-newline))
   8832                      (zero-or-more "\n    " (zero-or-more not-newline)))
   8833             line-end)
   8834    ;; The following is for Emacs 24 ‘check-declare-file’, which uses a
   8835    ;; less informative format.
   8836    (warning line-start "Warning (check-declare): " (file-name) " said "
   8837             (message (zero-or-more not-newline))
   8838             line-end))
   8839   :error-filter
   8840   (lambda (errors)
   8841     (flycheck-fill-empty-line-numbers
   8842      (flycheck-collapse-error-message-whitespace
   8843       (flycheck-sanitize-errors errors))))
   8844   :modes (emacs-lisp-mode lisp-interaction-mode)
   8845   :enabled flycheck--emacs-lisp-enabled-p
   8846   :predicate
   8847   (lambda ()
   8848     ;; Do not check buffers that should not be byte-compiled.  The checker
   8849     ;; process will refuse to compile these, which would confuse Flycheck
   8850     (not (bound-and-true-p no-byte-compile)))
   8851   :next-checkers (emacs-lisp-checkdoc))
   8852 
   8853 (defconst flycheck-emacs-lisp-checkdoc-form
   8854   (flycheck-prepare-emacs-lisp-form
   8855     (unless (require 'elisp-mode nil 'no-error)
   8856       ;; TODO: Fallback for Emacs 24, remove when dropping support for 24
   8857       (require 'lisp-mode))
   8858     (require 'checkdoc)
   8859 
   8860     (let ((source (car command-line-args-left))
   8861           ;; Remember the default directory of the process
   8862           (process-default-directory default-directory))
   8863       ;; Note that we deliberately use our custom approach even despite of
   8864       ;; `checkdoc-file' which was added to Emacs 25.1.  While it's conceptually
   8865       ;; the better thing, its implementation has too many flaws to be of use
   8866       ;; for us.
   8867       (with-temp-buffer
   8868         (insert-file-contents source 'visit)
   8869         (setq buffer-file-name source)
   8870         ;; And change back to the process default directory to make file-name
   8871         ;; back-substutition work
   8872         (setq default-directory process-default-directory)
   8873         (with-demoted-errors "Error in checkdoc: %S"
   8874           ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to
   8875           ;; parse sexps and identify docstrings correctly; see
   8876           ;; https://github.com/flycheck/flycheck/issues/833
   8877           (delay-mode-hooks (emacs-lisp-mode))
   8878           (setq delayed-mode-hooks nil)
   8879           (checkdoc-current-buffer t)
   8880           (with-current-buffer checkdoc-diagnostic-buffer
   8881             (princ (buffer-substring-no-properties (point-min) (point-max)))
   8882             (kill-buffer)))))))
   8883 
   8884 (defconst flycheck-emacs-lisp-checkdoc-variables
   8885   `(checkdoc-symbol-words
   8886     checkdoc-arguments-in-order-flag
   8887     checkdoc-force-history-flag
   8888     checkdoc-permit-comma-termination-flag
   8889     checkdoc-force-docstrings-flag
   8890     checkdoc-package-keywords-flag
   8891     checkdoc-spellcheck-documentation-flag
   8892     checkdoc-verb-check-experimental-flag
   8893     checkdoc-max-keyref-before-warn
   8894     sentence-end-double-space
   8895     ,@(and (>= emacs-major-version 28)
   8896            '(checkdoc-column-zero-backslash-before-paren)))
   8897   "Variables inherited by the checkdoc subprocess.")
   8898 
   8899 (defun flycheck-emacs-lisp-checkdoc-variables-form ()
   8900   "Make a sexp to pass relevant variables to a checkdoc subprocess.
   8901 
   8902 Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'."
   8903   `(progn
   8904      ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
   8905                 (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables))))
   8906 
   8907 (flycheck-define-checker emacs-lisp-checkdoc
   8908   "An Emacs Lisp style checker using CheckDoc.
   8909 
   8910 The checker runs `checkdoc-current-buffer'."
   8911   :command ("emacs" (eval flycheck-emacs-args)
   8912             "--eval" (eval (flycheck-sexp-to-string
   8913                             (flycheck-emacs-lisp-checkdoc-variables-form)))
   8914             "--eval" (eval flycheck-emacs-lisp-checkdoc-form)
   8915             "--" source)
   8916   :error-patterns
   8917   ((info line-start (file-name) ":" line ": " (message) line-end))
   8918   :modes (emacs-lisp-mode)
   8919   :enabled flycheck--emacs-lisp-checkdoc-enabled-p)
   8920 
   8921 (dolist (checker '(emacs-lisp emacs-lisp-checkdoc))
   8922   (setf (car (flycheck-checker-get checker 'command))
   8923         flycheck-this-emacs-executable))
   8924 
   8925 (defun flycheck-ember-template--check-for-config (&rest _ignored)
   8926   "Check the required config file is available up the file system."
   8927   (and buffer-file-name
   8928        (locate-dominating-file buffer-file-name ".template-lintrc.js")))
   8929 
   8930 (defun flycheck-ember-template--parse-error (output checker buffer)
   8931   "Parse Ember-template-lint errors/warnings from JSON OUTPUT.
   8932 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   8933 the BUFFER that was checked respectively."
   8934   (mapcar (lambda (err)
   8935             (let-alist err
   8936               (flycheck-error-new-at
   8937                .line
   8938                .column
   8939                (pcase .severity
   8940                  (2 'error)
   8941                  (1 'warning)
   8942                  (_ 'warning))
   8943                .message
   8944                :id .rule
   8945                :checker checker
   8946                :buffer buffer
   8947                :filename (buffer-file-name buffer))))
   8948           (cdr (car (car (flycheck-parse-json output))))))
   8949 
   8950 (flycheck-def-config-file-var flycheck-ember-template-lintrc
   8951     ember-template
   8952     ".template-lintrc.js")
   8953 
   8954 (flycheck-define-checker ember-template
   8955   "An Ember template checker using ember-template-lint."
   8956   :command ("ember-template-lint"
   8957             (config-file "--config-path" flycheck-ember-template-lintrc)
   8958             "--filename" source-original
   8959             "--format=json")
   8960   :standard-input t
   8961   :error-parser flycheck-ember-template--parse-error
   8962   :modes web-mode
   8963   :enabled flycheck-ember-template--check-for-config
   8964   :working-directory flycheck-ember-template--check-for-config)
   8965 
   8966 (flycheck-def-option-var flycheck-erlang-include-path nil erlang
   8967   "A list of include directories for Erlang.
   8968 
   8969 The value of this variable is a list of strings, where each
   8970 string is a directory to add to the include path of erlc.
   8971 Relative paths are relative to the file being checked."
   8972   :type '(repeat (directory :tag "Include directory"))
   8973   :safe #'flycheck-string-list-p
   8974   :package-version '(flycheck . "0.24"))
   8975 
   8976 (flycheck-def-option-var flycheck-erlang-library-path nil erlang
   8977   "A list of library directories for Erlang.
   8978 
   8979 The value of this variable is a list of strings, where each
   8980 string is a directory to add to the library path of erlc.
   8981 Relative paths are relative to the file being checked."
   8982   :type '(repeat (directory :tag "Library directory"))
   8983   :safe #'flycheck-string-list-p
   8984   :package-version '(flycheck . "0.24"))
   8985 
   8986 (flycheck-define-checker erlang
   8987   "An Erlang syntax checker using the Erlang interpreter.
   8988 
   8989 See URL `https://www.erlang.org/'."
   8990   :command ("erlc"
   8991             "-o" temporary-directory
   8992             (option-list "-I" flycheck-erlang-include-path)
   8993             (option-list "-pa" flycheck-erlang-library-path)
   8994             "-Wall"
   8995             source)
   8996   :error-patterns
   8997   ((warning line-start (file-name) ":" line ":" (optional column ":")
   8998             " Warning:" (message) line-end)
   8999    (error line-start (file-name) ":" line ":" (optional column ":") " "
   9000           (message) line-end))
   9001   :modes erlang-mode
   9002   :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name))))
   9003 
   9004 (defun flycheck--contains-rebar-config (dir-name)
   9005   "Return DIR-NAME if rebar config file exists in DIR-NAME, nil otherwise."
   9006   (when (or (file-exists-p (expand-file-name "rebar.config" dir-name))
   9007             (file-exists-p (expand-file-name "rebar.config.script" dir-name)))
   9008     dir-name))
   9009 
   9010 (defun flycheck--locate-rebar3-project-root
   9011     (file-name &optional prev-file-name acc)
   9012   "Find the top-most rebar project root for source FILE-NAME.
   9013 
   9014 A project root directory is any directory containing a
   9015 rebar.config file.  Find the top-most directory to move out of any
   9016 nested dependencies.
   9017 
   9018 FILE-NAME is a source file for which to find the project.
   9019 
   9020 PREV-FILE-NAME helps us prevent infinite looping
   9021 
   9022 ACC is an accumulator that keeps the list of results, the first
   9023 non-nil of which will be our project root.
   9024 
   9025 Return the absolute path to the directory"
   9026   (if (string= file-name prev-file-name)
   9027       (car (remove nil acc))
   9028     (let ((current-dir (file-name-directory file-name)))
   9029       (flycheck--locate-rebar3-project-root
   9030        (directory-file-name current-dir)
   9031        file-name
   9032        (cons (flycheck--contains-rebar-config current-dir) acc)))))
   9033 
   9034 (defun flycheck-rebar3-project-root (&optional _checker)
   9035   "Return directory where rebar.config is located."
   9036   (flycheck--locate-rebar3-project-root buffer-file-name))
   9037 
   9038 (flycheck-def-option-var flycheck-erlang-rebar3-profile nil erlang-rebar3
   9039   "The rebar3 profile to use.
   9040 
   9041 The profile used when compiling, if VALUE is nil \"test\" will be used
   9042 when the file is located in test directory, otherwise \"default\" will be
   9043 used as profile."
   9044   :type '(choice (const :tag "Automatic" nil)
   9045                  (string :tag "Profile"))
   9046   :safe #'flycheck-string-or-nil-p
   9047   :package-version '(flycheck . "32"))
   9048 
   9049 (defun flycheck-erlang-rebar3-get-profile ()
   9050   "Return rebar3 profile.
   9051 
   9052 Use flycheck-erlang-rebar3-profile if set, otherwise use test or eqc profile if
   9053 directory name is \"test\" or \"eqc\", or else \"default\"."
   9054   (or
   9055    flycheck-erlang-rebar3-profile
   9056    (with-no-warnings
   9057      ;; `seq-contains-p' is only in seq >= 2.21
   9058      (seq-contains '("test" "eqc")
   9059                    (and buffer-file-name
   9060                         (file-name-base
   9061                          (directory-file-name
   9062                           (file-name-directory buffer-file-name))))))
   9063    "default"))
   9064 
   9065 (flycheck-define-checker erlang-rebar3
   9066   "An Erlang syntax checker using the rebar3 build tool."
   9067   :command ("rebar3" "as" (eval (flycheck-erlang-rebar3-get-profile)) "compile")
   9068   :error-parser flycheck-parse-with-patterns-without-color
   9069   :error-patterns
   9070   ((warning line-start (file-name) ":" line ":" (optional column ":")
   9071             " Warning:" (message) line-end)
   9072    (error line-start (file-name) ":" line ":" (optional column ":") " "
   9073           (message) line-end))
   9074   :modes erlang-mode
   9075   :enabled flycheck-rebar3-project-root
   9076   :predicate flycheck-buffer-saved-p
   9077   :working-directory flycheck-rebar3-project-root)
   9078 
   9079 (flycheck-define-checker eruby-erubis
   9080   "An eRuby syntax checker using the `erubis' command.
   9081 
   9082 See URL `https://www.kuwata-lab.com/erubis/'."
   9083   :command ("erubis" "-z" source)
   9084   :error-patterns
   9085   ((error line-start (file-name) ":" line ": " (message) line-end))
   9086   :modes (html-erb-mode rhtml-mode)
   9087   :next-checkers ((warning . eruby-ruumba)))
   9088 
   9089 (flycheck-def-config-file-var flycheck-ruumbarc eruby-ruumba ".ruumba.yml")
   9090 
   9091 (flycheck-def-option-var flycheck-ruumba-lint-only nil eruby-ruumba
   9092   "Whether to only report code issues in Ruumba.
   9093 
   9094 When non-nil, only report code issues in Ruumba, via `--lint'.
   9095 Otherwise report style issues as well."
   9096   :safe #'booleanp
   9097   :type 'boolean
   9098   :package-version '(flycheck . "32"))
   9099 
   9100 (flycheck-define-checker eruby-ruumba
   9101   "An eRuby syntax and style checker using the Ruumba tool.
   9102 
   9103 You need at least Ruumba 0.1.7 for this syntax checker.
   9104 
   9105 See URL `https://github.com/ericqweinstein/ruumba'."
   9106   :command ("ruumba"
   9107             "--display-cop-names"
   9108             "--force-exclusion"
   9109             "--format" "emacs"
   9110             "--cache" "false"
   9111             (config-file "--config" flycheck-ruumbarc)
   9112             (option-flag "--lint" flycheck-ruumba-lint-only)
   9113             ;; Ruumba takes the original file name as argument when reading
   9114             ;; from standard input
   9115             "--stdin" source-original)
   9116   :standard-input t
   9117   :working-directory flycheck-ruby--find-project-root
   9118   :error-patterns
   9119   ((info line-start (file-name) ":" line ":" column ": C: "
   9120          (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
   9121    (warning line-start (file-name) ":" line ":" column ": W: "
   9122             (optional (id (one-or-more (not (any ":")))) ": ") (message)
   9123             line-end)
   9124    (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
   9125           (optional (id (one-or-more (not (any ":")))) ": ") (message)
   9126           line-end))
   9127   :modes (html-erb-mode rhtml-mode))
   9128 
   9129 (flycheck-def-args-var flycheck-gfortran-args fortran-gfortran
   9130   :package-version '(flycheck . "0.22"))
   9131 
   9132 (flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran
   9133   "A list of include directories for GCC Fortran.
   9134 
   9135 The value of this variable is a list of strings, where each
   9136 string is a directory to add to the include path of gcc.
   9137 Relative paths are relative to the file being checked."
   9138   :type '(repeat (directory :tag "Include directory"))
   9139   :safe #'flycheck-string-list-p
   9140   :package-version '(flycheck . "0.20"))
   9141 
   9142 (flycheck-def-option-var flycheck-gfortran-language-standard "f95"
   9143                          fortran-gfortran
   9144   "The language standard to use in GFortran.
   9145 
   9146 The value of this variable is either a string denoting a language
   9147 standard, or nil, to use the default standard.  When non-nil,
   9148 pass the language standard via the `-std' option."
   9149   :type '(choice (const :tag "Default standard" nil)
   9150                  (string :tag "Language standard"))
   9151   :package-version '(flycheck . "0.20"))
   9152 
   9153 (flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran
   9154   "The source code layout to use in GFortran.
   9155 
   9156 The value of this variable is one of the following symbols:
   9157 
   9158 nil
   9159      Let gfortran determine the layout from the extension
   9160 
   9161 `free'
   9162      Use free form layout
   9163 
   9164 
   9165 `fixed'
   9166      Use fixed form layout
   9167 
   9168 In any other case, an error is signaled."
   9169   :type '(choice (const :tag "Guess layout from extension" nil)
   9170                  (const :tag "Free form layout" free)
   9171                  (const :tag "Fixed form layout" fixed))
   9172   :safe (lambda (value) (or (not value) (memq value '(free fixed))))
   9173   :package-version '(flycheck . "0.20"))
   9174 
   9175 (defun flycheck-option-gfortran-layout (value)
   9176   "Option VALUE filter for `flycheck-gfortran-layout'."
   9177   (pcase value
   9178     (`nil nil)
   9179     (`free "free-form")
   9180     (`fixed "fixed-form")
   9181     (_ (error "Invalid value for flycheck-gfortran-layout: %S" value))))
   9182 
   9183 (flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra")
   9184                          fortran-gfortran
   9185   "A list of warnings for GCC Fortran.
   9186 
   9187 The value of this variable is a list of strings, where each string
   9188 is the name of a warning category to enable.  By default, all
   9189 recommended warnings and some extra warnings are enabled (as by
   9190 `-Wall' and `-Wextra' respectively).
   9191 
   9192 Refer to the gfortran manual at URL
   9193 `https://gcc.gnu.org/onlinedocs/gfortran/' for more information
   9194 about warnings"
   9195   :type '(choice (const :tag "No additional warnings" nil)
   9196                  (repeat :tag "Additional warnings"
   9197                          (string :tag "Warning name")))
   9198   :safe #'flycheck-string-list-p
   9199   :package-version '(flycheck . "0.20"))
   9200 
   9201 (flycheck-define-checker fortran-gfortran
   9202   "An Fortran syntax checker using GCC.
   9203 
   9204 Uses GCC's Fortran compiler gfortran.  See URL
   9205 `https://gcc.gnu.org/onlinedocs/gfortran/'."
   9206   :command ("gfortran"
   9207             "-fsyntax-only"
   9208             "-fshow-column"
   9209             ;; Do not visually indicate the source location
   9210             "-fno-diagnostics-show-caret"
   9211             ;; Do not show the corresponding warning group
   9212             "-fno-diagnostics-show-option"
   9213             ;; Fortran has similar include processing as C/C++
   9214             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   9215             (option "-std=" flycheck-gfortran-language-standard concat)
   9216             (option "-f" flycheck-gfortran-layout concat
   9217                     flycheck-option-gfortran-layout)
   9218             (option-list "-W" flycheck-gfortran-warnings concat)
   9219             (option-list "-I" flycheck-gfortran-include-path concat)
   9220             (eval flycheck-gfortran-args)
   9221             source)
   9222   :error-patterns
   9223   ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
   9224           (or (= 3 (zero-or-more not-newline) "\n") "")
   9225           (or "Error" "Fatal Error") ": "
   9226           (message) line-end)
   9227    (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
   9228             (or (= 3 (zero-or-more not-newline) "\n") "")
   9229             "Warning: " (message) line-end))
   9230   :modes (fortran-mode f90-mode))
   9231 
   9232 (flycheck-define-checker yaml-actionlint
   9233   "A YAML syntax checker using actionlint.
   9234 
   9235 See URL https://github.com/rhysd/actionlint/."
   9236   :command ("actionlint" "-oneline" source)
   9237   :error-patterns ((error line-start (file-name) ":" line ":" column ": " (message) line-end))
   9238   :modes (yaml-mode yaml-ts-mode)
   9239   :predicate (lambda ()
   9240                (string-match-p
   9241                 (rx (or ".github/workflows" ".github\\workflows"))
   9242                 (buffer-file-name))))
   9243 
   9244 (flycheck-define-checker go-gofmt
   9245   "A Go syntax and style checker using the gofmt utility.
   9246 
   9247 See URL `https://golang.org/cmd/gofmt/'."
   9248   :command ("gofmt")
   9249   :standard-input t
   9250   :error-patterns
   9251   ((error line-start "<standard input>:" line ":" column ": "
   9252           (message) line-end))
   9253   :modes (go-mode go-ts-mode)
   9254   :next-checkers ((warning . go-vet)
   9255                   ;; Fall back, if go-vet doesn't exist
   9256                   (warning . go-build) (warning . go-test)
   9257                   (warning . go-errcheck)
   9258                   (warning . go-unconvert)
   9259                   (warning . go-staticcheck)))
   9260 
   9261 (flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet
   9262   "A list of print-like functions for `go vet'.
   9263 
   9264 Go vet will check these functions for format string problems and
   9265 issues, such as a mismatch between the number of formats used,
   9266 and the number of arguments given.
   9267 
   9268 Each entry is in the form Name:N where N is the zero-based
   9269 argument position of the first argument involved in the print:
   9270 either the format or the first print argument for non-formatted
   9271 prints.  For example, if you have Warn and Warnf functions that
   9272 take an io.Writer as their first argument, like Fprintf,
   9273 -printfuncs=Warn:1,Warnf:1 "
   9274   :type '(repeat :tag "print-like functions"
   9275                  (string :tag "function"))
   9276   :safe #'flycheck-string-list-p)
   9277 
   9278 (flycheck-define-checker go-vet
   9279   "A Go syntax checker using the `go vet' command.
   9280 
   9281 See URL `https://golang.org/cmd/go/' and URL
   9282 `https://golang.org/cmd/vet/'."
   9283   :command ("go" "vet"
   9284             (option "-printf.funcs=" flycheck-go-vet-print-functions concat
   9285                     flycheck-option-comma-separated-list)
   9286             (source ".go"))
   9287   :error-patterns
   9288   ((warning line-start (file-name) ":" line ": " (message) line-end))
   9289   :modes (go-mode go-ts-mode)
   9290   :next-checkers (go-build
   9291                   go-test
   9292                   ;; Fall back if `go build' or `go test' can be used
   9293                   go-errcheck
   9294                   go-unconvert
   9295                   go-staticcheck)
   9296   :verify (lambda (_)
   9297             (let* ((go (flycheck-checker-executable 'go-vet))
   9298                    (have-vet (member "vet" (ignore-errors
   9299                                              (process-lines go "tool")))))
   9300               (list
   9301                (flycheck-verification-result-new
   9302                 :label "go tool vet"
   9303                 :message (if have-vet "present" "missing")
   9304                 :face (if have-vet 'success '(bold error)))))))
   9305 
   9306 (flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test)
   9307   "Whether to install dependencies in `go build' and `go test'.
   9308 
   9309 If non-nil automatically install dependencies with `go build'
   9310 while syntax checking."
   9311   :type 'boolean
   9312   :safe #'booleanp
   9313   :package-version '(flycheck . "0.25"))
   9314 
   9315 (flycheck-def-option-var flycheck-go-build-tags nil
   9316                          (go-build go-test go-errcheck go-staticcheck)
   9317   "A list of tags for `go build'.
   9318 
   9319 Each item is a string with a tag to be given to `go build'."
   9320   :type '(repeat (string :tag "Tag"))
   9321   :safe #'flycheck-string-list-p
   9322   :package-version '(flycheck . "0.25"))
   9323 
   9324 
   9325 (flycheck-def-option-var flycheck-go-version nil go-staticcheck
   9326   "The version of go that should be targeted by `staticcheck'.
   9327 
   9328 Should be a string representing a version, like 1.6 or 1.11.4.
   9329 See `https://staticcheck.io/docs/#targeting-go-versions' for
   9330 details."
   9331   :type '(choice (const :tag "Unspecified" nil)
   9332                  (string :tag "Version"))
   9333   :safe #'flycheck-string-or-nil-p
   9334   :package-version '(flycheck . "0.32"))
   9335 
   9336 (flycheck-define-checker go-build
   9337   "A Go syntax and type checker using the `go build' command.
   9338 
   9339 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
   9340   :command ("go" "build"
   9341             (option-flag "-i" flycheck-go-build-install-deps)
   9342             ;; multiple tags are listed as "dev debug ..."
   9343             (option-list "-tags=" flycheck-go-build-tags concat)
   9344             "-o" null-device)
   9345   :error-patterns
   9346   ((error line-start (file-name) ":" line ":"
   9347           (optional column ":") " "
   9348           (message (one-or-more not-newline)
   9349                    (zero-or-more "\n\t" (one-or-more not-newline)))
   9350           line-end)
   9351    ;; Catch error message about multiple packages in a directory, which doesn't
   9352    ;; follow the standard error message format.
   9353    (info line-start
   9354          (message "can't load package: package "
   9355                   (one-or-more (not (any ?: ?\n)))
   9356                   ": found packages "
   9357                   (one-or-more not-newline))
   9358          line-end))
   9359   :error-filter
   9360   (lambda (errors)
   9361     (dolist (error errors)
   9362       (unless (flycheck-error-line error)
   9363         ;; Flycheck ignores errors without line numbers, but the error
   9364         ;; message about multiple packages in a directory doesn't come with a
   9365         ;; line number, so inject a fake one.
   9366         (setf (flycheck-error-line error) 1)))
   9367     errors)
   9368   :modes (go-mode go-ts-mode)
   9369   :predicate (lambda ()
   9370                (and (flycheck-buffer-saved-p)
   9371                     (not (string-suffix-p "_test.go" (buffer-file-name)))))
   9372   :next-checkers ((warning . go-errcheck)
   9373                   (warning . go-unconvert)
   9374                   (warning . go-staticcheck)))
   9375 
   9376 (flycheck-define-checker go-test
   9377   "A Go syntax and type checker using the `go test' command.
   9378 
   9379 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
   9380   :command ("go" "test"
   9381             (option-flag "-i" flycheck-go-build-install-deps)
   9382             (option-list "-tags=" flycheck-go-build-tags concat)
   9383             "-c" "-o" null-device)
   9384   :error-patterns
   9385   ((error line-start (file-name) ":" line ":"
   9386           (optional column ":") " "
   9387           (message (one-or-more not-newline)
   9388                    (zero-or-more "\n\t" (one-or-more not-newline)))
   9389           line-end))
   9390   :modes (go-mode go-ts-mode)
   9391   :predicate
   9392   (lambda () (and (flycheck-buffer-saved-p)
   9393                   (string-suffix-p "_test.go" (buffer-file-name))))
   9394   :next-checkers ((warning . go-errcheck)
   9395                   (warning . go-unconvert)
   9396                   (warning . go-staticcheck)))
   9397 
   9398 (flycheck-define-checker go-errcheck
   9399   "A Go checker for unchecked errors.
   9400 
   9401 Requires errcheck newer than commit 8515d34 (Aug 28th, 2015).
   9402 
   9403 See URL `https://github.com/kisielk/errcheck'."
   9404   :command ("errcheck"
   9405             "-abspath"
   9406             (option-list "-tags=" flycheck-go-build-tags concat)
   9407             ".")
   9408   :error-patterns
   9409   ((warning line-start
   9410             (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t")
   9411             (message)
   9412             line-end))
   9413   :error-filter
   9414   (lambda (errors)
   9415     (let ((errors (flycheck-sanitize-errors errors)))
   9416       (dolist (err errors)
   9417         (when-let (message (flycheck-error-message err))
   9418           ;; Improve the messages reported by errcheck to make them more clear.
   9419           (setf (flycheck-error-message err)
   9420                 (format "Ignored `error` returned from `%s`" message)))))
   9421     errors)
   9422   :modes (go-mode go-ts-mode)
   9423   :predicate (lambda () (flycheck-buffer-saved-p))
   9424   :next-checkers ((warning . go-unconvert)
   9425                   (warning . go-staticcheck)))
   9426 
   9427 (flycheck-define-checker go-unconvert
   9428   "A Go checker looking for unnecessary type conversions.
   9429 
   9430 See URL `https://github.com/mdempsky/unconvert'."
   9431   :command ("unconvert" ".")
   9432   :error-patterns
   9433   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
   9434   :modes (go-mode go-ts-mode)
   9435   :predicate (lambda () (flycheck-buffer-saved-p)))
   9436 
   9437 (flycheck-define-checker go-staticcheck
   9438   "A Go checker that performs static analysis and linting using
   9439 the `staticcheck' command.
   9440 
   9441 `staticcheck' is explicitly fully compatible with \"the last two
   9442 versions of go\". `staticheck' can target earlier versions (with
   9443 limited features) if `flycheck-go-version' is set. See URL
   9444 `https://staticcheck.io/'."
   9445   :command ("staticcheck" "-f" "json"
   9446             (option-list "-tags" flycheck-go-build-tags concat)
   9447             (option "-go" flycheck-go-version))
   9448 
   9449   :error-parser flycheck-parse-go-staticcheck
   9450   :modes (go-mode go-ts-mode))
   9451 
   9452 (flycheck-define-checker groovy
   9453   "A groovy syntax checker using groovy compiler API.
   9454 
   9455 See URL `https://www.groovy-lang.org'."
   9456   :command ("groovy" "-e"
   9457             "import org.codehaus.groovy.control.*
   9458 
   9459 unit = new CompilationUnit()
   9460 unit.addSource(\"input\", System.in)
   9461 
   9462 try {
   9463     unit.compile(Phases.CONVERSION)
   9464 } catch (MultipleCompilationErrorsException e) {
   9465     e.errorCollector.write(new PrintWriter(System.out, true), null)
   9466 }")
   9467   :standard-input t
   9468   :error-patterns
   9469   ((error line-start "input: " line ":" (message)
   9470           " @ line " line ", column " column "." line-end))
   9471   :modes groovy-mode)
   9472 
   9473 (flycheck-define-checker haml
   9474   "A Haml syntax checker using the Haml compiler.
   9475 
   9476 See URL `https://haml.info'."
   9477   :command ("haml" "-c" "--stdin")
   9478   :standard-input t
   9479   :error-patterns
   9480   ((error line-start "Syntax error on line " line ": " (message) line-end)
   9481    (error line-start ":" line ": syntax error, " (message) line-end))
   9482   :modes haml-mode)
   9483 
   9484 (flycheck-define-checker haml-lint
   9485   "HAML-Lint style checker.
   9486 
   9487 See URL `https://github.com/sds/haml-lint'."
   9488   :command ("haml-lint" "--no-color" "--no-summary" source)
   9489   :error-patterns
   9490   ((error line-start (file-name) ":" line " [E]" (message) line-end)
   9491    (warning line-start (file-name) ":" line " [W]" (message) line-end))
   9492   :modes haml-mode)
   9493 
   9494 (flycheck-define-checker handlebars
   9495   "A Handlebars syntax checker using the Handlebars compiler.
   9496 
   9497 See URL `https://handlebarsjs.com/'."
   9498   :command ("handlebars" "-i-")
   9499   :standard-input t
   9500   :error-patterns
   9501   ((error line-start
   9502           "Error: Parse error on line " line ":" (optional "\r") "\n"
   9503           (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n"
   9504           (message) line-end))
   9505   :modes (handlebars-mode handlebars-sgml-mode web-mode)
   9506   :predicate
   9507   (lambda ()
   9508     (if (eq major-mode 'web-mode)
   9509         ;; Check if this is a handlebars file since web-mode does not store the
   9510         ;; non-canonical engine name
   9511         (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps))
   9512                (pattern (cdr (assoc "handlebars" regexp-alist))))
   9513           (and pattern (buffer-file-name)
   9514                (string-match-p pattern (buffer-file-name))))
   9515       t)))
   9516 
   9517 (defconst flycheck-haskell-module-re
   9518   (rx line-start (zero-or-more (or "\n" (any space)))
   9519       "module" (one-or-more (or "\n" (any space)))
   9520       (group (one-or-more (not (any space "(" "\n")))))
   9521   "Regular expression for a Haskell module name.")
   9522 
   9523 (flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc)
   9524   :package-version '(flycheck . "0.22"))
   9525 
   9526 (flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc
   9527   "Whether to enable nix support in stack.
   9528 
   9529 When non-nil, stack will append '--nix' flag to any call."
   9530   :type 'boolean
   9531   :safe #'booleanp
   9532   :package-version '(flycheck . "26"))
   9533 
   9534 (flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc
   9535   "Override project stack.yaml file.
   9536 
   9537 The value of this variable is a file path that refers to a yaml
   9538 file for the current stack project. Relative file paths are
   9539 resolved against the checker's working directory. When non-nil,
   9540 stack will get overridden value via `--stack-yaml'."
   9541   :type '(choice (const :tag "Unspecified" nil)
   9542                  (file :tag "Project file"))
   9543   :safe #'flycheck-string-or-nil-p
   9544   :package-version '(flycheck . "32"))
   9545 
   9546 (flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc
   9547   "Whether to disable the user package database in GHC.
   9548 
   9549 When non-nil, disable the user package database in GHC, via
   9550 `-no-user-package-db'."
   9551   :type 'boolean
   9552   :safe #'booleanp
   9553   :package-version '(flycheck . "0.16"))
   9554 
   9555 (flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc
   9556   "Additional module databases for GHC.
   9557 
   9558 The value of this variable is a list of strings, where each
   9559 string is a directory of a package database.  Each package
   9560 database is given to GHC via `-package-db'."
   9561   :type '(repeat (directory :tag "Package database"))
   9562   :safe #'flycheck-string-list-p
   9563   :package-version '(flycheck . "0.16"))
   9564 
   9565 (flycheck-def-option-var flycheck-ghc-search-path nil
   9566                          (haskell-stack-ghc haskell-ghc)
   9567   "Module search path for (Stack) GHC.
   9568 
   9569 The value of this variable is a list of strings, where each
   9570 string is a directory containing Haskell modules.  Each directory
   9571 is added to the GHC search path via `-i'."
   9572   :type '(repeat (directory :tag "Module directory"))
   9573   :safe #'flycheck-string-list-p
   9574   :package-version '(flycheck . "0.16"))
   9575 
   9576 (flycheck-def-option-var flycheck-ghc-language-extensions nil
   9577                          (haskell-stack-ghc haskell-ghc)
   9578   "Language extensions for (Stack) GHC.
   9579 
   9580 The value of this variable is a list of strings, where each
   9581 string is a Haskell language extension, as in the LANGUAGE
   9582 pragma.  Each extension is enabled via `-X'."
   9583   :type '(repeat (string :tag "Language extension"))
   9584   :safe #'flycheck-string-list-p
   9585   :package-version '(flycheck . "0.19"))
   9586 
   9587 (defvar flycheck-haskell-ghc-cache-directory nil
   9588   "The cache directory for `ghc' output.")
   9589 
   9590 (defun flycheck-haskell-ghc-cache-directory ()
   9591   "Get the cache location for `ghc' output.
   9592 
   9593 If no cache directory exists yet, create one and return it.
   9594 Otherwise return the previously used cache directory."
   9595   (setq flycheck-haskell-ghc-cache-directory
   9596         (or flycheck-haskell-ghc-cache-directory
   9597             (make-temp-file "flycheck-haskell-ghc-cache" 'directory))))
   9598 
   9599 (defun flycheck--locate-dominating-file-matching (directory regexp)
   9600   "Search for a file in directory hierarchy starting at DIRECTORY.
   9601 
   9602 Look up the directory hierarchy from DIRECTORY for a directory
   9603 containing a file that matches REGEXP."
   9604   (locate-dominating-file
   9605    directory
   9606    (lambda (dir)
   9607      (directory-files dir nil regexp t))))
   9608 
   9609 (defun flycheck-haskell--find-stack-default-directory ()
   9610   "Find a directory to run haskell-stack-ghc.
   9611 
   9612 Return a parent directory with a stack*.y[a]ml file, or the
   9613 directory returned by \"stack path --project-root\"."
   9614   (or
   9615    (when (buffer-file-name)
   9616      (flycheck--locate-dominating-file-matching
   9617       (file-name-directory (buffer-file-name))
   9618       (rx "stack" (* any) "." (or "yml" "yaml") eos)))
   9619    (when-let* ((stack (funcall flycheck-executable-find "stack"))
   9620                (output (ignore-errors
   9621                          (process-lines stack
   9622                                         "--no-install-ghc"
   9623                                         "path" "--project-root")))
   9624                (stack-dir (car output)))
   9625      (and (file-directory-p stack-dir) stack-dir))))
   9626 
   9627 (defun flycheck-haskell--ghc-find-default-directory (_checker)
   9628   "Find a parent directory containing a cabal or package.yaml file."
   9629   (when (buffer-file-name)
   9630     (flycheck--locate-dominating-file-matching
   9631      (file-name-directory (buffer-file-name))
   9632      "\\.cabal\\'\\|\\`package\\.yaml\\'")))
   9633 
   9634 (flycheck-define-checker haskell-stack-ghc
   9635   "A Haskell syntax and type checker using `stack ghc'.
   9636 
   9637 See URL `https://github.com/commercialhaskell/stack'."
   9638   :command ("stack"
   9639             "--no-install-ghc"
   9640             (option "--stack-yaml" flycheck-ghc-stack-project-file)
   9641             (option-flag "--nix" flycheck-ghc-stack-use-nix)
   9642             "ghc" "--" "-Wall" "-no-link"
   9643             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
   9644             (option-list "-X" flycheck-ghc-language-extensions concat)
   9645             (option-list "-i" flycheck-ghc-search-path concat)
   9646             (eval (concat
   9647                    "-i"
   9648                    (flycheck-module-root-directory
   9649                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
   9650             (eval flycheck-ghc-args)
   9651             "-x" (eval
   9652                   (pcase major-mode
   9653                     (`haskell-mode "hs")
   9654                     (`haskell-literate-mode "lhs")))
   9655             source)
   9656   :error-patterns
   9657   ((warning line-start (file-name) ":" line ":" column ":"
   9658             (or " " "\n    ") (in "Ww") "arning:"
   9659             (optional " " "[" (id (one-or-more not-newline)) "]")
   9660             (optional "\n")
   9661             (message
   9662              (one-or-more " ") (one-or-more not-newline)
   9663              (zero-or-more "\n"
   9664                            (one-or-more " ")
   9665                            (one-or-more (not (any ?\n ?|)))))
   9666             line-end)
   9667    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
   9668           (optional " " "[" (id (one-or-more not-newline)) "]")
   9669           (or (message (one-or-more not-newline))
   9670               (and "\n"
   9671                    (message
   9672                     (one-or-more " ") (one-or-more not-newline)
   9673                     (zero-or-more "\n"
   9674                                   (one-or-more " ")
   9675                                   (one-or-more (not (any ?\n ?|)))))))
   9676           line-end))
   9677   :error-filter
   9678   (lambda (errors)
   9679     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
   9680   :modes (haskell-mode haskell-literate-mode)
   9681   :next-checkers ((warning . haskell-hlint))
   9682   :working-directory (lambda (_)
   9683                        (flycheck-haskell--find-stack-default-directory))
   9684   :enabled flycheck-haskell--find-stack-default-directory
   9685   :verify (lambda (_)
   9686             (let* ((stack (flycheck-haskell--find-stack-default-directory)))
   9687               (list
   9688                (flycheck-verification-result-new
   9689                 :label "stack config"
   9690                 :message (or stack "Not found")
   9691                 :face (if stack 'success '(bold error)))))))
   9692 
   9693 (flycheck-define-checker haskell-ghc
   9694   "A Haskell syntax and type checker using ghc.
   9695 
   9696 See URL `https://www.haskell.org/ghc/'."
   9697   :command ("ghc" "-Wall" "-no-link"
   9698             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
   9699             (option-flag "-no-user-package-db"
   9700                          flycheck-ghc-no-user-package-database)
   9701             (option-list "-package-db" flycheck-ghc-package-databases)
   9702             (option-list "-i" flycheck-ghc-search-path concat)
   9703             ;; Include the parent directory of the current module tree, to
   9704             ;; properly resolve local imports
   9705             (eval (concat
   9706                    "-i"
   9707                    (flycheck-module-root-directory
   9708                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
   9709             (option-list "-X" flycheck-ghc-language-extensions concat)
   9710             (eval flycheck-ghc-args)
   9711             "-x" (eval
   9712                   (pcase major-mode
   9713                     (`haskell-mode "hs")
   9714                     (`haskell-literate-mode "lhs")))
   9715             source)
   9716   :error-patterns
   9717   ((warning line-start (file-name) ":" line ":" column ":"
   9718             (or " " "\n    ") (in "Ww") "arning:"
   9719             (optional " " "[" (id (one-or-more not-newline)) "]")
   9720             (optional "\n")
   9721             (message
   9722              (one-or-more " ") (one-or-more not-newline)
   9723              (zero-or-more "\n"
   9724                            (one-or-more " ")
   9725                            (one-or-more (not (any ?\n ?|)))))
   9726             line-end)
   9727    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
   9728           (optional " " "[" (id (one-or-more not-newline)) "]")
   9729           (or (message (one-or-more not-newline))
   9730               (and "\n"
   9731                    (message
   9732                     (one-or-more " ") (one-or-more not-newline)
   9733                     (zero-or-more "\n"
   9734                                   (one-or-more " ")
   9735                                   (one-or-more (not (any ?\n ?|)))))))
   9736           line-end))
   9737   :error-filter
   9738   (lambda (errors)
   9739     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
   9740   :modes (haskell-mode haskell-literate-mode)
   9741   :next-checkers ((warning . haskell-hlint))
   9742   :working-directory flycheck-haskell--ghc-find-default-directory)
   9743 
   9744 (flycheck-def-config-file-var flycheck-hlintrc haskell-hlint ".hlint.yaml")
   9745 
   9746 (flycheck-def-args-var flycheck-hlint-args haskell-hlint
   9747   :package-version '(flycheck . "0.25"))
   9748 
   9749 (flycheck-def-option-var flycheck-hlint-language-extensions
   9750     nil haskell-hlint
   9751   "Extensions list to enable for hlint.
   9752 
   9753 The value of this variable is a list of strings, where each
   9754 string is a name of extension to enable in
   9755 hlint (e.g. \"QuasiQuotes\")."
   9756   :type '(repeat :tag "Extensions" (string :tag "Extension"))
   9757   :safe #'flycheck-string-list-p
   9758   :package-version '(flycheck . "0.24"))
   9759 
   9760 (flycheck-def-option-var flycheck-hlint-ignore-rules
   9761     nil haskell-hlint
   9762   "Ignore rules list for hlint checks.
   9763 
   9764 The value of this variable is a list of strings, where each
   9765 string is an ignore rule (e.g. \"Use fmap\")."
   9766   :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule"))
   9767   :safe #'flycheck-string-list-p
   9768   :package-version '(flycheck . "0.24"))
   9769 
   9770 (flycheck-def-option-var flycheck-hlint-hint-packages
   9771     nil haskell-hlint
   9772   "Hint packages to include for hlint checks.
   9773 
   9774 The value of this variable is a list of strings, where each
   9775 string is a default hint package (e.g. (\"Generalise\"
   9776 \"Default\" \"Dollar\"))."
   9777   :type '(repeat :tag "Hint packages" (string :tag "Hint package"))
   9778   :safe #'flycheck-string-list-p
   9779   :package-version '(flycheck . "0.24"))
   9780 
   9781 (flycheck-define-checker haskell-hlint
   9782   "A Haskell style checker using hlint.
   9783 
   9784 See URL `https://github.com/ndmitchell/hlint'."
   9785   :command ("hlint"
   9786             "--no-exit-code"
   9787             (option-list "-X" flycheck-hlint-language-extensions concat)
   9788             (option-list "-i=" flycheck-hlint-ignore-rules concat)
   9789             (option-list "-h" flycheck-hlint-hint-packages concat)
   9790             (config-file "-h" flycheck-hlintrc)
   9791             (eval flycheck-hlint-args)
   9792             source-inplace)
   9793   :error-patterns
   9794   ((info line-start
   9795          (file-name) ":"
   9796          (or (seq line ":" column (optional "-" end-column))
   9797              (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9798          ": Suggestion: "
   9799          (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9800          line-end)
   9801    (warning line-start
   9802             (file-name) ":"
   9803             (or (seq line ":" column (optional "-" end-column))
   9804                 (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9805             ": Warning: "
   9806             (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9807             line-end)
   9808    (error line-start
   9809           (file-name) ":"
   9810           (or (seq line ":" column (optional "-" end-column))
   9811               (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9812           ": Error: "
   9813           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9814           line-end))
   9815   :modes (haskell-mode haskell-literate-mode))
   9816 
   9817 (flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc")
   9818 
   9819 (flycheck-define-checker html-tidy
   9820   "A HTML syntax and style checker using Tidy.
   9821 
   9822 See URL `https://github.com/htacg/tidy-html5'."
   9823   :command ("tidy" (config-file "-config" flycheck-tidyrc)
   9824             "-lang" "en"
   9825             "-e" "-q")
   9826   :standard-input t
   9827   :error-patterns
   9828   ((error line-start
   9829           "line " line
   9830           " column " column
   9831           " - Error: " (message) line-end)
   9832    (warning line-start
   9833             "line " line
   9834             " column " column
   9835             " - Warning: " (message) line-end))
   9836   :modes (html-mode mhtml-mode nxhtml-mode))
   9837 
   9838 (flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc")
   9839 
   9840 (flycheck-def-option-var flycheck-jshint-extract-javascript nil
   9841                          javascript-jshint
   9842   "Whether jshint should extract Javascript from HTML.
   9843 
   9844 If nil no extract rule is given to jshint.  If `auto' only
   9845 extract Javascript if a HTML file is detected.  If `always' or
   9846 `never' extract Javascript always or never respectively.
   9847 
   9848 Refer to the jshint manual at the URL
   9849 `https://jshint.com/docs/cli/#flags' for more information."
   9850   :type
   9851   '(choice (const :tag "No extraction rule" nil)
   9852            (const :tag "Try to extract Javascript when detecting HTML files"
   9853                   auto)
   9854            (const :tag "Always try to extract Javascript" always)
   9855            (const :tag "Never try to extract Javascript" never))
   9856   :safe #'symbolp
   9857   :package-version '(flycheck . "26"))
   9858 
   9859 (flycheck-define-checker javascript-jshint
   9860   "A Javascript syntax and style checker using jshint.
   9861 
   9862 See URL `https://www.jshint.com'."
   9863   :command ("jshint" "--reporter=checkstyle"
   9864             "--filename" source-original
   9865             (config-file "--config" flycheck-jshintrc)
   9866             (option "--extract=" flycheck-jshint-extract-javascript
   9867                     concat flycheck-option-symbol)
   9868             "-")
   9869   :standard-input t
   9870   :error-parser flycheck-parse-checkstyle
   9871   :error-filter
   9872   (lambda (errors)
   9873     (flycheck-remove-error-file-names
   9874      "stdin" (flycheck-dequalify-error-ids errors)))
   9875   :modes (js-mode js2-mode js3-mode rjsx-mode js-ts-mode))
   9876 
   9877 (flycheck-def-args-var flycheck-eslint-args javascript-eslint
   9878   :package-version '(flycheck . "32"))
   9879 
   9880 (flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint
   9881   "A list of directories with custom rules for ESLint.
   9882 
   9883 The value of this variable is a list of strings, where each
   9884 string is a directory with custom rules for ESLint.
   9885 
   9886 Refer to the ESLint manual at URL
   9887 `https://eslint.org/docs/user-guide/command-line-interface#--rulesdir'
   9888 for more information about the custom directories."
   9889   :type '(repeat (directory :tag "Custom rules directory"))
   9890   :safe #'flycheck-string-list-p
   9891   :package-version '(flycheck . "29"))
   9892 
   9893 (defun flycheck-eslint-config-exists-p ()
   9894   "Whether there is a valid eslint config for the current buffer."
   9895   (eql 0 (flycheck-call-checker-process
   9896           'javascript-eslint nil nil nil
   9897           "--print-config" (or buffer-file-name "index.js"))))
   9898 
   9899 (defun flycheck-parse-eslint (output checker buffer)
   9900   "Parse ESLint errors/warnings from JSON OUTPUT.
   9901 
   9902 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   9903 the BUFFER that was checked respectively.
   9904 
   9905 See URL `https://eslint.org' for more information about ESLint."
   9906   (mapcar (lambda (err)
   9907             (let-alist err
   9908               (flycheck-error-new-at
   9909                .line
   9910                .column
   9911                (pcase .severity
   9912                  (2 'error)
   9913                  (1 'warning)
   9914                  (_ 'warning))
   9915                .message
   9916                :id .ruleId
   9917                :checker checker
   9918                :buffer buffer
   9919                :filename (buffer-file-name buffer)
   9920                :end-line .endLine
   9921                :end-column .endColumn)))
   9922           (let-alist (caar (flycheck-parse-json output))
   9923             .messages)))
   9924 
   9925 (defun flycheck-eslint--find-working-directory (_checker)
   9926   "Look for a working directory to run ESLint CHECKER in.
   9927 
   9928 This will be the directory that contains the `node_modules'
   9929 directory.  If no such directory is found in the directory
   9930 hierarchy, it looks first for `.eslintignore' and then for
   9931 `.eslintrc' files to detect the project root."
   9932   (let* ((regex-config (concat "\\`\\.eslintrc"
   9933                                "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'")))
   9934     (when buffer-file-name
   9935       (or (locate-dominating-file buffer-file-name "node_modules")
   9936           (locate-dominating-file buffer-file-name ".eslintignore")
   9937           (locate-dominating-file
   9938            (file-name-directory buffer-file-name)
   9939            (lambda (directory)
   9940              (> (length (directory-files directory nil regex-config t)) 0)))))))
   9941 
   9942 (flycheck-define-checker javascript-eslint
   9943   "A Javascript syntax and style checker using eslint.
   9944 
   9945 See URL `https://eslint.org/'."
   9946   :command ("eslint" "--format=json"
   9947             (option-list "--rulesdir" flycheck-eslint-rules-directories)
   9948             (eval flycheck-eslint-args)
   9949             "--stdin" "--stdin-filename" source-original)
   9950   :standard-input t
   9951   :error-parser flycheck-parse-eslint
   9952   :enabled (lambda () (flycheck-eslint-config-exists-p))
   9953   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
   9954                   typescript-mode js-ts-mode typescript-ts-mode tsx-ts-mode)
   9955   :working-directory flycheck-eslint--find-working-directory
   9956   :verify
   9957   (lambda (_)
   9958     (let* ((default-directory
   9959              (flycheck-compute-working-directory 'javascript-eslint))
   9960            (have-config (flycheck-eslint-config-exists-p)))
   9961       (list
   9962        (flycheck-verification-result-new
   9963         :label "config file"
   9964         :message (if have-config "found" "missing or incorrect")
   9965         :face (if have-config 'success '(bold error))))))
   9966   :error-explainer
   9967   (lambda (err)
   9968     (let ((error-code (flycheck-error-id err))
   9969           (url "https://eslint.org/docs/rules/%s"))
   9970       (and error-code
   9971            ;; skip non-builtin rules
   9972            (not ;; `seq-contains-p' is only in seq >= 2.21
   9973             (with-no-warnings (seq-contains error-code ?/)))
   9974            `(url . ,(format url error-code))))))
   9975 
   9976 (flycheck-define-checker javascript-standard
   9977   "A Javascript code and style checker for the (Semi-)Standard Style.
   9978 
   9979 This checker works with `standard' and `semistandard', defaulting
   9980 to the former.  To use it with the latter, set
   9981 `flycheck-javascript-standard-executable' to `semistandard'.
   9982 
   9983 See URL `https://github.com/standard/standard' and URL
   9984 `https://github.com/Flet/semistandard'."
   9985   :command ("standard" "--stdin")
   9986   :standard-input t
   9987   :error-patterns
   9988   ((error line-start "  <text>:" line ":" column ":" (message) line-end))
   9989   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
   9990                   js-ts-mode))
   9991 
   9992 (flycheck-define-checker json-jsonlint
   9993   "A JSON syntax and style checker using jsonlint.
   9994 
   9995 See URL `https://github.com/zaach/jsonlint'."
   9996   ;; We can't use standard input for jsonlint, because it doesn't output errors
   9997   ;; anymore when using -c -q with standard input :/
   9998   :command ("jsonlint" "-c" "-q" source)
   9999   :error-patterns
  10000   ((error line-start
  10001           (file-name)
  10002           ": line " line
  10003           ", col " column ", "
  10004           (message) line-end))
  10005   :error-filter
  10006   (lambda (errors)
  10007     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
  10008   :modes (json-mode js-json-mode json-ts-mode))
  10009 
  10010 (flycheck-define-checker json-python-json
  10011   "A JSON syntax checker using Python json.tool module.
  10012 
  10013 See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'."
  10014   :command ("python3" "-m" "json.tool" source
  10015             ;; Send the pretty-printed output to the null device
  10016             null-device)
  10017   :error-patterns
  10018   ((error line-start
  10019           (message) ": line " line " column " column
  10020           ;; Ignore the rest of the line which shows the char position.
  10021           (one-or-more not-newline)
  10022           line-end))
  10023   :modes (json-mode js-json-mode json-ts-mode)
  10024   ;; The JSON parser chokes if the buffer is empty and has no JSON inside
  10025   :predicate flycheck-buffer-nonempty-p)
  10026 
  10027 (flycheck-define-checker json-jq
  10028   "JSON checker using the jq tool.
  10029 
  10030 This checker accepts multiple consecutive JSON values in a
  10031 single input, which is useful for jsonlines data.
  10032 
  10033 See URL `https://stedolan.github.io/jq/'."
  10034   :command ("jq" "." source null-device)
  10035   ;; Example error message:
  10036   ;;   parse error: Expected another key-value pair at line 3, column 1
  10037   :error-patterns
  10038   ((error line-start
  10039           (optional "parse error: ")
  10040           (message) "at line " line ", column " column
  10041           (zero-or-more not-newline) line-end))
  10042   :modes (json-mode js-json-mode json-ts-mode))
  10043 
  10044 (flycheck-define-checker jsonnet
  10045   "A Jsonnet syntax checker using the jsonnet binary.
  10046 
  10047 See URL `https://jsonnet.org'."
  10048   :command ("jsonnet" source-inplace)
  10049   :error-patterns
  10050   ((error line-start "STATIC ERROR: " (file-name) ":"
  10051           (or (seq line ":" column (zero-or-one (seq "-" end-column)))
  10052               (seq "(" line ":" column ")" "-"
  10053                    "(" end-line ":" end-column ")"))
  10054           ": " (message) line-end)
  10055    (error line-start "RUNTIME ERROR: " (message) "\n"
  10056           (? "\t" (file-name) ":" ;; first line of the backtrace
  10057              (or (seq line ":" column (zero-or-one (seq "-" end-column)))
  10058                  (seq "(" line ":" column ")" "-"
  10059                       "(" end-line ":" end-column ")")))))
  10060   :error-filter
  10061   (lambda (errs)
  10062     ;; Some errors are missing line numbers. See URL
  10063     ;; `https://github.com/google/jsonnet/issues/786'.
  10064     (dolist (err errs)
  10065       (unless (flycheck-error-line err)
  10066         (setf (flycheck-error-line err) 1)))
  10067     (flycheck-sanitize-errors errs))
  10068   :modes jsonnet-mode)
  10069 
  10070 (flycheck-define-checker less
  10071   "A LESS syntax checker using lessc.
  10072 
  10073 Requires lessc 1.4 or newer.
  10074 
  10075 See URL `https://lesscss.org'."
  10076   :command ("lessc" "--lint" "--no-color"
  10077             "-")
  10078   :standard-input t
  10079   :error-patterns
  10080   ((error line-start (one-or-more word) ":"
  10081           (message)
  10082           " in - on line " line
  10083           ", column " column ":"
  10084           line-end))
  10085   :modes less-css-mode)
  10086 
  10087 (flycheck-define-checker less-stylelint
  10088   "A LESS syntax and style checker using stylelint.
  10089 
  10090 See URL `https://stylelint.io/'."
  10091   :command ("stylelint"
  10092             (eval flycheck-stylelint-args)
  10093             (option-flag "--quiet" flycheck-stylelint-quiet)
  10094             (config-file "--config" flycheck-stylelintrc))
  10095   :standard-input t
  10096   :verify (lambda (_) (flycheck--stylelint-verify 'less-stylelint))
  10097   :error-parser flycheck-parse-stylelint
  10098   :predicate flycheck-buffer-nonempty-p
  10099   :modes (less-css-mode))
  10100 
  10101 (flycheck-define-checker llvm-llc
  10102   "Flycheck LLVM IR checker using llc.
  10103 
  10104 See URL `https://llvm.org/docs/CommandGuide/llc.html'."
  10105   :command ("llc" "-o" null-device source)
  10106   :error-patterns
  10107   ((error line-start
  10108           ;; llc prints the executable path
  10109           (zero-or-one (minimal-match (one-or-more not-newline)) ": ")
  10110           (file-name) ":" line ":" column ": error: " (message)
  10111           line-end))
  10112   :error-filter
  10113   (lambda (errors)
  10114     ;; sanitize errors occurring in inline assembly
  10115     (flycheck-sanitize-errors
  10116      (flycheck-remove-error-file-names "<inline asm>" errors)))
  10117   :modes llvm-mode)
  10118 
  10119 (flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc")
  10120 
  10121 (flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck
  10122   "The standards to use in luacheck.
  10123 
  10124 The value of this variable is either a list of strings denoting
  10125 the standards to use, or nil to pass nothing to luacheck.  When
  10126 non-nil, pass the standards via one or more `--std' options."
  10127   :type '(choice (const :tag "Default" nil)
  10128                  (repeat :tag "Custom standards"
  10129                          (string :tag "Standard name")))
  10130   :safe #'flycheck-string-list-p)
  10131 (make-variable-buffer-local 'flycheck-luacheck-standards)
  10132 
  10133 (flycheck-define-checker lua-luacheck
  10134   "A Lua syntax checker using luacheck.
  10135 
  10136 See URL `https://github.com/mpeterv/luacheck'."
  10137   :command ("luacheck"
  10138             "--formatter" "plain"
  10139             "--codes"                   ; Show warning codes
  10140             "--no-color"
  10141             (option-list "--std" flycheck-luacheck-standards)
  10142             (config-file "--config" flycheck-luacheckrc)
  10143             "--filename" source-original
  10144             ;; Read from standard input
  10145             "-")
  10146   :standard-input t
  10147   :error-patterns
  10148   ((warning line-start
  10149             (optional (file-name))
  10150             ":" line ":" column
  10151             ": (" (id "W" (one-or-more digit)) ") "
  10152             (message) line-end)
  10153    (error line-start
  10154           (optional (file-name))
  10155           ":" line ":" column ":"
  10156           ;; `luacheck' before 0.11.0 did not output codes for errors, hence
  10157           ;; the ID is optional here
  10158           (optional " (" (id "E" (one-or-more digit)) ") ")
  10159           (message) line-end))
  10160   :modes (lua-mode lua-ts-mode))
  10161 
  10162 (flycheck-define-checker lua
  10163   "A Lua syntax checker using the Lua compiler.
  10164 
  10165 See URL `https://www.lua.org/'."
  10166   :command ("luac" "-p" "-")
  10167   :standard-input t
  10168   :error-patterns
  10169   ((error line-start
  10170           ;; Skip the name of the luac executable.
  10171           (minimal-match (zero-or-more not-newline))
  10172           ": stdin:" line ": " (message) line-end))
  10173   :modes (lua-mode lua-ts-mode))
  10174 
  10175 (flycheck-define-checker opam
  10176   "A Opam syntax and style checker using opam lint.
  10177 
  10178 See URL `https://opam.ocaml.org/doc/man/opam-lint.html'."
  10179   :command ("opam" "lint" "-")
  10180   :standard-input t
  10181   :error-patterns
  10182   ((error line-start                    ; syntax error
  10183           (one-or-more space) "error  " (id ?2)
  10184           ": File format error"
  10185           (or (and " at line " line ", column " column ": " (message))
  10186               (and ": " (message)))
  10187           line-end)
  10188    (error line-start
  10189           (one-or-more space) "error  " (id ?3)
  10190           (minimal-match (zero-or-more not-newline))
  10191           "at line " line ", column " column ": " (message)
  10192           line-end)
  10193    (error line-start
  10194           (one-or-more space) "error " (id (one-or-more num))
  10195           ": " (message (one-or-more not-newline))
  10196           line-end)
  10197    (warning line-start
  10198             (one-or-more space) "warning " (id (one-or-more num))
  10199             ": " (message)
  10200             line-end))
  10201   :error-filter
  10202   (lambda (errors)
  10203     (flycheck-increment-error-columns
  10204      (flycheck-fill-empty-line-numbers errors)))
  10205   :modes tuareg-opam-mode)
  10206 
  10207 (flycheck-def-option-var flycheck-perl-include-path nil perl
  10208   "A list of include directories for Perl.
  10209 
  10210 The value of this variable is a list of strings, where each
  10211 string is a directory to add to the include path of Perl.
  10212 Relative paths are relative to the file being checked."
  10213   :type '(repeat (directory :tag "Include directory"))
  10214   :safe #'flycheck-string-list-p
  10215   :package-version '(flycheck . "0.24"))
  10216 
  10217 (flycheck-def-option-var flycheck-perl-module-list nil perl
  10218   "A list of modules to use for Perl.
  10219 
  10220 The value of this variable is a list of strings, where each
  10221 string is a module to `use' in Perl."
  10222   :type '(repeat :tag "Module")
  10223   :safe #'flycheck-string-list-p
  10224   :package-version '(flycheck . "32"))
  10225 
  10226 (flycheck-define-checker perl
  10227   "A Perl syntax checker using the Perl interpreter.
  10228 
  10229 See URL `https://www.perl.org'."
  10230   :command ("perl" "-w" "-c"
  10231             (option-list "-I" flycheck-perl-include-path)
  10232             (option-list "-M" flycheck-perl-module-list concat))
  10233   :standard-input t
  10234   :error-patterns
  10235   ((error line-start (minimal-match (message))
  10236           " at - line " line
  10237           (or "." (and ", " (zero-or-more not-newline))) line-end))
  10238   :modes (perl-mode cperl-mode)
  10239   :next-checkers (perl-perlcritic))
  10240 
  10241 (flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic
  10242   "The message severity for Perl Critic.
  10243 
  10244 The value of this variable is a severity level as integer, for
  10245 the `--severity' option to Perl Critic."
  10246   :type '(integer :tag "Severity level")
  10247   :safe #'integerp
  10248   :package-version '(flycheck . "0.18"))
  10249 
  10250 (flycheck-def-option-var flycheck-perlcritic-theme nil perl-perlcritic
  10251   "The theme expression for Perl Critic.
  10252 
  10253 The value of this variable is passed as the `--theme' option to
  10254 `Perl::Critic'.  See the documentation of `Perl::Critic' for
  10255 details."
  10256   :type '(choice (const :tag "None" nil)
  10257                  (string :tag "Theme expression"))
  10258   :safe #'flycheck-string-or-nil-p
  10259   :package-version '(flycheck . "32-csv"))
  10260 
  10261 (flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic
  10262                               ".perlcriticrc"
  10263   :package-version '(flycheck . "26"))
  10264 
  10265 (flycheck-define-checker perl-perlcritic
  10266   "A Perl syntax checker using Perl::Critic.
  10267 
  10268 See URL `https://metacpan.org/pod/Perl::Critic'."
  10269   :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n"
  10270             (config-file "--profile" flycheck-perlcriticrc)
  10271             (option "--severity" flycheck-perlcritic-severity nil
  10272                     flycheck-option-int)
  10273             (option "--theme" flycheck-perlcritic-theme))
  10274   :standard-input t
  10275   :error-patterns
  10276   ((info line-start
  10277          "STDIN/" line "/" column "/" (any "1") "/"
  10278          (id (one-or-more (not (any "/")))) "/" (message)
  10279          line-end)
  10280    (warning line-start
  10281             "STDIN/" line "/" column "/" (any "234") "/"
  10282             (id (one-or-more (not (any "/")))) "/" (message)
  10283             line-end)
  10284    (error line-start
  10285           "STDIN/" line "/" column "/" (any "5") "/"
  10286           (id (one-or-more (not (any "/")))) "/" (message)
  10287           line-end))
  10288   :modes (cperl-mode perl-mode)
  10289   :next-checkers (perl-perlimports)
  10290 
  10291   :error-explainer
  10292   (lambda (err)
  10293     (let ((error-code (flycheck-error-id err))
  10294           (url "https://metacpan.org/pod/Perl::Critic::Policy::%s"))
  10295       (and error-code `(url . ,(format url error-code))))))
  10296 
  10297 (defun flycheck-perl-perlimports-parse-errors (output checker buffer)
  10298   "Parse perlimports json output errors from OUTPUT.
  10299 
  10300 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
  10301 the BUFFER that was checked respectively.
  10302 
  10303 See URL `https://metacpan.org/dist/App-perlimports/view/script/perlimports'
  10304 for more information about perlimports."
  10305   (mapcar (lambda (err)
  10306             (let-alist err
  10307               (flycheck-error-new-at
  10308                .location.start.line
  10309                .location.start.column
  10310                'info
  10311                (concat .module " " .reason ":"
  10312                        (with-temp-buffer
  10313                          (insert (substring .diff (string-match-p "\n" .diff)))
  10314                          (diff-mode)
  10315                          (font-lock-ensure)
  10316                          (buffer-string)))
  10317                :end-line .location.end.line
  10318                :end-column .location.end.column
  10319                :checker checker
  10320                :buffer buffer)))
  10321           (flycheck-parse-json output)))
  10322 
  10323 (flycheck-define-checker perl-perlimports
  10324   "A checker for cleaning up Perl import statements.
  10325 
  10326 See URL `https://metacpan.org/dist/App-perlimports/view/script/perlimports'."
  10327   :command ("perlimports"
  10328             "--filename" source
  10329             "--json"
  10330             "--lint"
  10331             "--no-preserve-duplicates"
  10332             "--no-preserve-unused"
  10333             "--no-tidy-whitespace"
  10334             "--read-stdin")
  10335   :standard-input t
  10336   :error-parser flycheck-perl-perlimports-parse-errors
  10337   :modes (cperl-mode perl-mode))
  10338 
  10339 (flycheck-define-checker php
  10340   "A PHP syntax checker using the PHP command line interpreter.
  10341 
  10342 See URL `https://php.net/manual/en/features.commandline.php'."
  10343   :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
  10344             "-d" "log_errors=0" source)
  10345   :error-patterns
  10346   ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " "
  10347           (message) " in " (file-name) " on line " line line-end))
  10348   :modes (php-mode php-ts-mode php+-mode)
  10349   :next-checkers ((warning . php-phpmd)
  10350                   (warning . php-phpcs)))
  10351 
  10352 (flycheck-def-option-var flycheck-phpmd-rulesets
  10353     '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode")
  10354     php-phpmd
  10355   "The rule sets for PHP Mess Detector.
  10356 
  10357 Set default rule sets and custom rule set files.
  10358 
  10359 See section \"Using multiple rule sets\" in the PHP Mess Detector
  10360 manual at URL `https://phpmd.org/documentation/index.html'."
  10361   :type '(repeat :tag "rule sets"
  10362                  (string :tag "A filename or rule set"))
  10363   :safe #'flycheck-string-list-p)
  10364 
  10365 (flycheck-define-checker php-phpmd
  10366   "A PHP style checker using PHP Mess Detector.
  10367 
  10368 See URL `https://phpmd.org/'."
  10369   :command ("phpmd" source "xml"
  10370             (eval (flycheck-option-comma-separated-list
  10371                    flycheck-phpmd-rulesets)))
  10372   :error-parser flycheck-parse-phpmd
  10373   :modes (php-mode php-ts-mode php+-mode)
  10374   :next-checkers (php-phpcs))
  10375 
  10376 (flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs
  10377   "The coding standard for PHP CodeSniffer.
  10378 
  10379 When nil, use the default standard from the global PHP
  10380 CodeSniffer configuration.  When set to a string, pass the string
  10381 to PHP CodeSniffer which will interpret it as name as a standard,
  10382 or as path to a standard specification."
  10383   :type '(choice (const :tag "Default standard" nil)
  10384                  (string :tag "Standard name or file"))
  10385   :safe #'flycheck-string-or-nil-p)
  10386 
  10387 (flycheck-define-checker php-phpcs
  10388   "A PHP style checker using PHP Code Sniffer.
  10389 
  10390 Needs PHP Code Sniffer 2.6 or newer.
  10391 
  10392 See URL `https://pear.php.net/package/PHP_CodeSniffer/'."
  10393   :command ("phpcs" "--report=checkstyle"
  10394             ;; Use -q flag to force quiet mode
  10395             ;; Quiet mode prevents errors from extra output when phpcs has
  10396             ;; been configured with show_progress enabled
  10397             "-q"
  10398             (option "--standard=" flycheck-phpcs-standard concat)
  10399             ;; Some files are not detected correctly
  10400             ;; so it is necessary to pass the extension.
  10401             (eval
  10402              (when-let* ((fname buffer-file-name)
  10403                          (ext (file-name-extension fname)))
  10404                (concat "--extensions=" ext)))
  10405 
  10406             ;; Pass original file name to phpcs.  We need to concat explicitly
  10407             ;; here, because phpcs really insists to get option and argument as
  10408             ;; a single command line argument :|
  10409             (eval (when (buffer-file-name)
  10410                     (concat "--stdin-path=" (buffer-file-name))))
  10411             ;; Read from standard input
  10412             "-")
  10413   :standard-input t
  10414   :error-parser flycheck-parse-checkstyle
  10415   :error-filter
  10416   (lambda (errors)
  10417     (flycheck-sanitize-errors
  10418      (flycheck-remove-error-file-names "STDIN" errors)))
  10419   :modes (php-mode php-ts-mode php+-mode)
  10420   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
  10421   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
  10422   :predicate flycheck-buffer-nonempty-p)
  10423 
  10424 (flycheck-define-checker php-phpcs-changed
  10425   "A PHP style checker using PHPCS-Changed.
  10426    Needs PHP Code Sniffer 2.6 or newer.
  10427    See `https://github.com/sirbrillig/phpcs-changed'."
  10428   :command ("phpcs-changed"
  10429             "--git"
  10430             "--git-base trunk"
  10431             "--git-unstaged"
  10432             (option "--standard=" flycheck-phpcs-standard concat)
  10433             (eval (buffer-file-name))
  10434             )
  10435   :standard-input t
  10436   :error-parser flycheck-parse-checkstyle
  10437   :error-filter
  10438   (lambda (errors)
  10439     (flycheck-sanitize-errors
  10440      (flycheck-remove-error-file-names "STDIN" errors)))
  10441   :modes (php-mode php+-mode)
  10442   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
  10443   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
  10444   :predicate flycheck-buffer-nonempty-p)
  10445 
  10446 (flycheck-define-checker processing
  10447   "Processing command line tool.
  10448 
  10449 See https://github.com/processing/processing/wiki/Command-Line"
  10450   :command ("processing-java" "--force"
  10451             ;; Don't change the order of these arguments, processing is pretty
  10452             ;; picky
  10453             (eval (concat "--sketch=" (file-name-directory (buffer-file-name))))
  10454             (eval (concat "--output=" (flycheck-temp-dir-system)))
  10455             "--build")
  10456   :error-patterns
  10457   ((error line-start (file-name) ":" line ":" column
  10458           (zero-or-more (or digit ":")) (message) line-end))
  10459   :modes processing-mode
  10460   ;; This syntax checker needs a file name
  10461   :predicate (lambda () (buffer-file-name)))
  10462 
  10463 (defun flycheck-proselint-parse-errors (output checker buffer)
  10464   "Parse proselint json output errors from OUTPUT.
  10465 
  10466 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
  10467 the BUFFER that was checked respectively.
  10468 
  10469 See URL `https://proselint.com/' for more information about proselint."
  10470   (mapcar (lambda (err)
  10471             (let-alist err
  10472               (flycheck-error-new-at-pos
  10473                .start
  10474                (pcase .severity
  10475                  (`"suggestion" 'info)
  10476                  (`"warning"    'warning)
  10477                  (`"error"      'error)
  10478                  ;; Default to error
  10479                  (_             'error))
  10480                .message
  10481                :id .check
  10482                :buffer buffer
  10483                :checker checker
  10484                ;; See https://github.com/amperser/proselint/issues/1048
  10485                :end-pos .end)))
  10486           (let-alist (car (flycheck-parse-json output))
  10487             .data.errors)))
  10488 
  10489 (flycheck-define-checker proselint
  10490   "Flycheck checker using Proselint.
  10491 
  10492 See URL `https://proselint.com/'."
  10493   :command ("proselint" "--json" "-")
  10494   :standard-input t
  10495   :error-parser flycheck-proselint-parse-errors
  10496   :modes (text-mode markdown-mode gfm-mode message-mode org-mode))
  10497 
  10498 (flycheck-def-option-var flycheck-protoc-import-path nil protobuf-protoc
  10499   "A list of directories to resolve import directives.
  10500 
  10501 The value of this variable is a list of strings, where each
  10502 string is a directory to add to the import path.  Relative paths
  10503 are relative to the file being checked."
  10504   :type '(repeat (directory :tag "Import directory"))
  10505   :safe #'flycheck-string-list-p
  10506   :package-version '(flycheck . "32"))
  10507 
  10508 (flycheck-define-checker protobuf-protoc
  10509   "A protobuf syntax checker using the protoc compiler.
  10510 
  10511 See URL `https://developers.google.com/protocol-buffers/'."
  10512   :command ("protoc" "--error_format" "gcc"
  10513             (eval (concat "--java_out=" (flycheck-temp-dir-system)))
  10514             ;; Add the current directory to resolve imports
  10515             (eval (concat "--proto_path="
  10516                           (file-name-directory (buffer-file-name))))
  10517             ;; Add other import paths; this needs to be after the current
  10518             ;; directory to produce the right output.  See URL
  10519             ;; `https://github.com/flycheck/flycheck/pull/1655'
  10520             (option-list "--proto_path=" flycheck-protoc-import-path concat)
  10521             source-inplace)
  10522   :error-patterns
  10523   ((info line-start (file-name) ":" line ":" column
  10524          ": note: " (message) line-end)
  10525    (error line-start (file-name) ":" line ":" column
  10526           ": " (message) line-end)
  10527    (error line-start
  10528           (message "In file included from") " " (file-name) ":" line ":"
  10529           column ":" line-end))
  10530   :modes protobuf-mode
  10531   :predicate (lambda () (buffer-file-name)))
  10532 
  10533 (defun flycheck-prototool-project-root (&optional _checker)
  10534   "Return the nearest directory holding the prototool.yaml configuration."
  10535   (and buffer-file-name
  10536        (locate-dominating-file buffer-file-name "prototool.yaml")))
  10537 
  10538 (flycheck-define-checker protobuf-prototool
  10539   "A protobuf syntax checker using prototool.
  10540 
  10541 See URL `https://github.com/uber/prototool'."
  10542   :command ("prototool" "lint" source-original)
  10543   :error-patterns
  10544   ((warning line-start (file-name) ":" line ":" column ":" (message) line-end))
  10545   :modes protobuf-mode
  10546   :enabled flycheck-prototool-project-root
  10547   :predicate flycheck-buffer-saved-p)
  10548 
  10549 (flycheck-define-checker pug
  10550   "A Pug syntax checker using the pug compiler.
  10551 
  10552 See URL `https://pugjs.org/'."
  10553   :command ("pug" "-p" (eval (expand-file-name (buffer-file-name))))
  10554   :standard-input t
  10555   :error-patterns
  10556   ;; errors with includes/extends (e.g. missing files)
  10557   ((error "Error: " (message) (zero-or-more not-newline) "\n"
  10558           (zero-or-more not-newline) "at "
  10559           (zero-or-more not-newline) " line " line)
  10560    ;; error when placing anything other than a mixin or
  10561    ;; block at the top-level of an extended template
  10562    ;; also unknown filters
  10563    (error line-start "Error: " (file-name) ":"
  10564           line ":" column "\n\n" (message) line-end)
  10565    ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.)
  10566    (error line-start
  10567           (optional "Type") "Error: "  (file-name) ":"
  10568           line (optional ":" column)
  10569           (zero-or-more not-newline) "\n"
  10570           (one-or-more (or (zero-or-more not-newline) "|"
  10571                            (zero-or-more not-newline) "\n")
  10572                        (zero-or-more "-")  (zero-or-more not-newline) "|"
  10573                        (zero-or-more not-newline) "\n")
  10574           (zero-or-more not-newline) "\n"
  10575           (one-or-more
  10576            (zero-or-more not-newline) "|"
  10577            (zero-or-more not-newline) "\n")
  10578           (zero-or-more not-newline) "\n"
  10579           (message)
  10580           line-end))
  10581   :modes pug-mode)
  10582 
  10583 (flycheck-define-checker puppet-parser
  10584   "A Puppet DSL syntax checker using puppet's own parser.
  10585 
  10586 See URL `https://puppet.com/'."
  10587   :command ("puppet" "parser" "validate" "--color=false")
  10588   :standard-input t
  10589   :error-patterns
  10590   (
  10591    ;; Patterns for Puppet 4
  10592    (error line-start "Error: Could not parse for environment "
  10593           (one-or-more (in "a-z" "0-9" "_")) ":"
  10594           (message) "(line: " line ", column: " column ")" line-end)
  10595    ;; Errors from Puppet < 4
  10596    (error line-start "Error: Could not parse for environment "
  10597           (one-or-more (in "a-z" "0-9" "_")) ":"
  10598           (message (minimal-match (one-or-more anything)))
  10599           " at line " line line-end)
  10600    (error line-start
  10601           ;; Skip over the path of the Puppet executable
  10602           (minimal-match (zero-or-more not-newline))
  10603           ": Could not parse for environment " (one-or-more word)
  10604           ": " (message (minimal-match (zero-or-more anything)))
  10605           " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end))
  10606   :modes (puppet-mode puppet-ts-mode)
  10607   :next-checkers ((warning . puppet-lint)))
  10608 
  10609 (flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint
  10610                               ".puppet-lint.rc"
  10611   :package-version '(flycheck . "26"))
  10612 
  10613 (flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint
  10614   "Disabled checkers for `puppet-lint'.
  10615 
  10616 The value of this variable is a list of strings, where each
  10617 string is the name of a check to disable (e.g. \"80chars\" or
  10618 \"double_quoted_strings\").
  10619 
  10620 See URL `https://puppet-lint.com/checks/' for a list of all checks
  10621 and their names."
  10622   :type '(repeat (string :tag "Check Name"))
  10623   :package-version '(flycheck . "26"))
  10624 
  10625 (defun flycheck-puppet-lint-disabled-arg-name (check)
  10626   "Create an argument to disable a puppetlint CHECK."
  10627   (concat "--no-" check "-check"))
  10628 
  10629 (flycheck-define-checker puppet-lint
  10630   "A Puppet DSL style checker using puppet-lint.
  10631 
  10632 See URL `https://puppet-lint.com/'."
  10633   ;; We must check the original file, because Puppetlint is quite picky on the
  10634   ;; names of files and there place in the directory structure, to comply with
  10635   ;; Puppet's autoload directory layout.  For instance, a class foo::bar is
  10636   ;; required to be in a file foo/bar.pp.  Any other place, such as a Flycheck
  10637   ;; temporary file will cause an error.
  10638   :command ("puppet-lint"
  10639             (config-file "--config" flycheck-puppet-lint-rc)
  10640             "--log-format"
  10641             "%{path}:%{line}:%{kind}: %{message} (%{check})"
  10642             (option-list "" flycheck-puppet-lint-disabled-checks concat
  10643                          flycheck-puppet-lint-disabled-arg-name)
  10644             source-original)
  10645   :error-patterns
  10646   ((warning line-start (file-name) ":" line ":warning: " (message) line-end)
  10647    (error line-start (file-name) ":" line ":error: " (message) line-end))
  10648   :modes (puppet-mode puppet-ts-mode)
  10649   ;; Since we check the original file, we can only use this syntax checker if
  10650   ;; the buffer is actually linked to a file, and if it is not modified.
  10651   :predicate flycheck-buffer-saved-p)
  10652 
  10653 (defun flycheck-python-run-snippet (checker snippet)
  10654   "Run a python SNIPPET and return the output.
  10655 
  10656 CHECKER's executable is assumed to be a Python REPL."
  10657   (when-let (output (flycheck-call-checker-process-for-output
  10658                      checker nil nil "-c" snippet))
  10659     (string-trim output)))
  10660 
  10661 (defun flycheck-python-get-path (checker)
  10662   "Compute the current Python path (CHECKER is a Python REPL) ."
  10663   (flycheck-python-run-snippet checker "import sys; print(sys.path[1:])"))
  10664 
  10665 (defun flycheck-python-find-module (checker module)
  10666   "Check if a Python MODULE is available (CHECKER is a Python REPL)."
  10667   (flycheck-python-run-snippet
  10668    checker (concat "import sys; sys.path.pop(0);"
  10669                    (format "import %s; print(%s.__file__)" module module))))
  10670 
  10671 (defun flycheck-python-needs-module-p (checker)
  10672   "Determine whether CHECKER needs to be invoked through Python.
  10673 
  10674 Previous versions of Flycheck called pylint and flake8 directly,
  10675 while new version call them through `python -c'.  This check
  10676 ensures that we don't break existing code; it also allows people
  10677 who use virtualenvs to run globally-installed checkers."
  10678   (not (string-match-p (rx (or "pylint" "pylint3" "flake8")
  10679                            (or "-script.pyw" ".exe" ".bat" "")
  10680                            eos)
  10681                        (flycheck-checker-executable checker))))
  10682 
  10683 (defun flycheck-python-verify-module (checker module)
  10684   "Verify that a Python MODULE is available.
  10685 
  10686 Return nil if CHECKER's executable is not a Python REPL.  This
  10687 function's is suitable for a checker's :verify."
  10688   (when (flycheck-python-needs-module-p checker)
  10689     (let ((mod-path (flycheck-python-find-module checker module)))
  10690       (list (flycheck-verification-result-new
  10691              :label (format "`%s' module" module)
  10692              :message (if mod-path (format "Found at %S" mod-path)
  10693                         (format "Missing; sys.path is %s"
  10694                                 (flycheck-python-get-path checker)))
  10695              :face (if mod-path 'success '(bold error)))))))
  10696 
  10697 (defun flycheck-python-module-args (checker module-name)
  10698   "Compute arguments to pass to CHECKER's executable to run MODULE-NAME.
  10699 
  10700 Return nil if CHECKER's executable is not a Python REPL.
  10701 Otherwise, return a list starting with -c (-m is not enough
  10702 because it adds the current directory to Python's path)."
  10703   (when (flycheck-python-needs-module-p checker)
  10704     `("-c" ,(concat "import sys;sys.path.pop(0);import runpy;"
  10705                     (format "runpy.run_module(%S, run_name='__main__')" module-name )))))
  10706 
  10707 (defcustom flycheck-python-project-files
  10708   '("pyproject.toml" "setup.cfg" "mypy.ini" "pyrightconfig.json")
  10709   "Files used to find where to run Python checkers from.
  10710 Currently used for pylint, flake8, and pyright.
  10711 
  10712 The presence of one in these files indicates the root of the
  10713 current project; `.pylintrc' is not part of the list because it
  10714 is commonly found in ~/."
  10715   :group 'flycheck
  10716   :type '(repeat (string :tag "File name"))
  10717   :package-version '(flycheck . "33")
  10718   :safe #'flycheck-string-list-p)
  10719 
  10720 (defun flycheck-python-find-project-root (_checker)
  10721   "Find the root directory of a Python project.
  10722 
  10723 The root directory is assumed to be the nearest parent directory
  10724 that contains one of `flycheck-python-project-files'.  If no such
  10725 file is found, we use the same heuristic as epylint: the nearest
  10726 parent directory that doesn't have a __init__.py file."
  10727   (let ((start (if buffer-file-name
  10728                    (file-name-directory buffer-file-name)
  10729                  default-directory)))
  10730     (or (flycheck--locate-dominating-file-matching
  10731          start (regexp-opt flycheck-python-project-files))
  10732         (locate-dominating-file
  10733          start (lambda (dir)
  10734                  (not (file-exists-p (expand-file-name "__init__.py" dir))))))))
  10735 
  10736 (flycheck-def-config-file-var flycheck-flake8rc python-flake8
  10737                               '(".flake8" "setup.cfg" "tox.ini"))
  10738 
  10739 (flycheck-def-option-var flycheck-flake8-error-level-alist
  10740     '(("^E9.*$"  . error)               ; Syntax errors from pep8
  10741       ("^F82.*$" . error)               ; undefined variables from pyflakes
  10742       ("^F83.*$" . error)               ; Duplicate arguments from flake8
  10743       ("^D.*$"   . info)                ; Docstring issues from flake8-pep257
  10744       ("^N.*$"   . info)                ; Naming issues from pep8-naming
  10745       )
  10746     python-flake8
  10747   "An alist mapping flake8 error IDs to Flycheck error levels.
  10748 
  10749 Each item in this list is a cons cell `(PATTERN . LEVEL)' where
  10750 PATTERN is a regular expression matched against the error ID, and
  10751 LEVEL is a Flycheck error level symbol.
  10752 
  10753 Each PATTERN is matched in the order of appearance in this list
  10754 against the error ID.  If it matches the ID, the level of the
  10755 corresponding error is set to LEVEL.  An error that is not
  10756 matched by any PATTERN defaults to warning level.
  10757 
  10758 The default value of this option matches errors from flake8
  10759 itself and from the following flake8 plugins:
  10760 
  10761 - pep8-naming
  10762 - flake8-pep257
  10763 
  10764 You may add your own mappings to this option in order to support
  10765 further flake8 plugins."
  10766   :type '(repeat (cons (regexp :tag "Error ID pattern")
  10767                        (symbol :tag "Error level")))
  10768   :package-version '(flycheck . "0.22"))
  10769 
  10770 (flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8
  10771   "The maximum McCabe complexity of methods.
  10772 
  10773 If nil, do not check the complexity of methods.  If set to an
  10774 integer, report any complexity greater than the value of this
  10775 variable as warning.
  10776 
  10777 If set to an integer, this variable overrules any similar setting
  10778 in the configuration file denoted by `flycheck-flake8rc'."
  10779   :type '(choice (const :tag "Do not check McCabe complexity" nil)
  10780                  (integer :tag "Maximum complexity"))
  10781   :safe #'integerp)
  10782 
  10783 (flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8
  10784   "The maximum length of lines.
  10785 
  10786 If set to an integer, the value of this variable denotes the
  10787 maximum length of lines, overruling any similar setting in the
  10788 configuration file denoted by `flycheck-flake8rc'.  An error will
  10789 be reported for any line longer than the value of this variable.
  10790 
  10791 If set to nil, use the maximum line length from the configuration
  10792 file denoted by `flycheck-flake8rc', or the PEP 8 recommendation
  10793 of 79 characters if there is no configuration with this setting."
  10794   :type '(choice (const :tag "Default value")
  10795                  (integer :tag "Maximum line length in characters"))
  10796   :safe #'integerp)
  10797 
  10798 (defun flycheck-flake8-fix-error-level (err)
  10799   "Fix the error level of ERR.
  10800 
  10801 Update the error level of ERR according to
  10802 `flycheck-flake8-error-level-alist'."
  10803   (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist)
  10804     (when (string-match-p pattern (flycheck-error-id err))
  10805       (setf (flycheck-error-level err) level)))
  10806   err)
  10807 
  10808 (defun flycheck-flake8--find-project-root (_checker)
  10809   "Find setup.cfg in a parent directory of the current buffer."
  10810   ;; This is a workaround for `https://gitlab.com/pycqa/flake8/issues/517'; see
  10811   ;; also `https://github.com/flycheck/flycheck/issues/1722'
  10812   (locate-dominating-file (or buffer-file-name default-directory) "setup.cfg"))
  10813 
  10814 (flycheck-define-checker python-flake8
  10815   "A Python syntax and style checker using Flake8.
  10816 
  10817 Requires Flake8 3.0 or newer. See URL
  10818 `https://flake8.readthedocs.io/'."
  10819   ;; Not calling flake8 directly makes it easier to switch between different
  10820   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
  10821   :command ("python3"
  10822             (eval (flycheck-python-module-args 'python-flake8 "flake8"))
  10823             "--format=default"
  10824             (config-file "--append-config" flycheck-flake8rc)
  10825             (option "--max-complexity" flycheck-flake8-maximum-complexity nil
  10826                     flycheck-option-int)
  10827             (option "--max-line-length" flycheck-flake8-maximum-line-length nil
  10828                     flycheck-option-int)
  10829             (eval (when buffer-file-name
  10830                     (concat "--stdin-display-name=" buffer-file-name)))
  10831             "-")
  10832   :standard-input t
  10833   :working-directory flycheck-python-find-project-root
  10834   :error-filter (lambda (errors)
  10835                   (let ((errors (flycheck-sanitize-errors errors)))
  10836                     (seq-map #'flycheck-flake8-fix-error-level errors)))
  10837   :error-patterns
  10838   ((warning line-start
  10839             (file-name) ":" line ":" (optional column ":") " "
  10840             (id (one-or-more (any alpha)) (one-or-more digit)) " "
  10841             (message (one-or-more not-newline))
  10842             line-end))
  10843   :enabled (lambda ()
  10844              (or (not (flycheck-python-needs-module-p 'python-flake8))
  10845                  (flycheck-python-find-module 'python-flake8 "flake8")))
  10846   :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8"))
  10847   :modes (python-mode python-ts-mode)
  10848   :next-checkers ((warning . python-pylint)
  10849                   (warning . python-mypy)))
  10850 
  10851 (flycheck-def-config-file-var flycheck-python-ruff-config python-ruff
  10852                               '("pyproject.toml" "ruff.toml" ".ruff.toml"))
  10853 
  10854 (flycheck-define-checker python-ruff
  10855   "A Python syntax and style checker using Ruff.
  10856 
  10857 See URL `https://docs.astral.sh/ruff/'."
  10858   :command ("ruff"
  10859             "check"
  10860             (config-file "--config" flycheck-python-ruff-config)
  10861             "--output-format=concise"
  10862             (option "--stdin-filename" buffer-file-name)
  10863             "-")
  10864   :standard-input t
  10865   :error-filter (lambda (errors)
  10866                   (let* ((errors (flycheck-sanitize-errors errors))
  10867                          (errors-with-ids (seq-filter #'flycheck-error-id errors)))
  10868                     (seq-union
  10869                      (seq-difference errors errors-with-ids)
  10870                      (seq-map #'flycheck-flake8-fix-error-level errors-with-ids))))
  10871   :error-patterns
  10872   ((error line-start
  10873           (or "-" (file-name)) ":" line ":" (optional column ":") " "
  10874           "SyntaxError: "
  10875           (message (one-or-more not-newline))
  10876           line-end)
  10877    (warning line-start
  10878             (or "-" (file-name)) ":" line ":" (optional column ":") " "
  10879             (id (one-or-more (any alpha)) (one-or-more digit) " ")
  10880             (message (one-or-more not-newline))
  10881             line-end))
  10882   :working-directory flycheck-python-find-project-root 
  10883   :modes (python-mode python-ts-mode)
  10884   :next-checkers ((warning . python-mypy)))
  10885 
  10886 (flycheck-def-config-file-var
  10887     flycheck-pylintrc python-pylint
  10888     '("pylintrc" ".pylintrc" "pyproject.toml" "setup.cfg"))
  10889 
  10890 (flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint
  10891   "Whether to use pylint message symbols or message codes.
  10892 
  10893 A pylint message has both an opaque identifying code (such as `F0401') and a
  10894 more meaningful symbolic code (such as `import-error').  This option governs
  10895 which should be used and reported to the user."
  10896   :type 'boolean
  10897   :safe #'booleanp
  10898   :package-version '(flycheck . "0.25"))
  10899 
  10900 (defun flycheck-parse-pylint (output checker buffer)
  10901   "Parse JSON OUTPUT of CHECKER on BUFFER as Pylint errors."
  10902   (mapcar (lambda (err)
  10903             (let-alist err
  10904               ;; Pylint can return -1 as a line or a column, hence the call to
  10905               ;; `max'.  See `https://github.com/flycheck/flycheck/issues/1383'.
  10906               (flycheck-error-new-at
  10907                (and .line (max .line 1))
  10908                (and .column (max (1+ .column) 1))
  10909                (pcase .type
  10910                  ;; See "pylint/utils.py"
  10911                  ((or "fatal" "error") 'error)
  10912                  ((or "info" "convention") 'info)
  10913                  ((or "warning" "refactor" _) 'warning))
  10914                ;; Drop lines showing the error in context
  10915                (and (string-match (rx (*? nonl) eol) .message)
  10916                     (match-string 0 .message))
  10917                :id (if flycheck-pylint-use-symbolic-id .symbol .message-id)
  10918                :checker checker
  10919                :buffer buffer
  10920                :filename .path)))
  10921           (car (flycheck-parse-json output))))
  10922 
  10923 (flycheck-define-checker python-pylint
  10924   "A Python syntax and style checker using Pylint.
  10925 
  10926 This syntax checker requires Pylint 1.0 or newer.
  10927 
  10928 See URL `https://www.pylint.org/'."
  10929   ;; --reports=n disables the scoring report.
  10930   ;; Not calling pylint directly makes it easier to switch between different
  10931   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
  10932   :command ("python3"
  10933             (eval (flycheck-python-module-args 'python-pylint "pylint"))
  10934             "--reports=n"
  10935             "--output-format=json"
  10936             (config-file "--rcfile=" flycheck-pylintrc concat)
  10937             ;; Need `source-inplace' for relative imports (e.g. `from .foo
  10938             ;; import bar'), see https://github.com/flycheck/flycheck/issues/280
  10939             source-inplace)
  10940   :error-parser flycheck-parse-pylint
  10941   :working-directory flycheck-python-find-project-root
  10942   :enabled (lambda ()
  10943              (or (not (flycheck-python-needs-module-p 'python-pylint))
  10944                  (flycheck-python-find-module 'python-pylint "pylint")))
  10945   :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint"))
  10946   :error-explainer (lambda (err)
  10947                      (when-let (id (flycheck-error-id err))
  10948                        (apply
  10949                         #'flycheck-call-checker-process-for-output
  10950                         'python-pylint nil t
  10951                         (append
  10952                          (flycheck-python-module-args 'python-pylint "pylint")
  10953                          (list (format "--help-msg=%s" id))))))
  10954   :modes (python-mode python-ts-mode)
  10955   :next-checkers ((warning . python-mypy)))
  10956 
  10957 (flycheck-define-checker python-pycompile
  10958   "A Python syntax checker using Python's builtin compiler.
  10959 
  10960 See URL `https://docs.python.org/3.4/library/py_compile.html'."
  10961   :command ("python3" "-m" "py_compile" source)
  10962   :error-patterns
  10963   ;; Python 2.7
  10964   ((error line-start "  File \"" (file-name) "\", line " line "\n"
  10965           (>= 2 (zero-or-more not-newline) "\n")
  10966           "SyntaxError: " (message) line-end)
  10967    (error line-start "Sorry: IndentationError: "
  10968           (message) "(" (file-name) ", line " line ")"
  10969           line-end)
  10970    ;; 2.6
  10971    (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'"))))
  10972           "', ('" (file-name (one-or-more (not (any "'")))) "', "
  10973           line ", " column ", " (one-or-more not-newline) line-end))
  10974   :working-directory flycheck-python-find-project-root
  10975   :modes (python-mode python-ts-mode)
  10976   :next-checkers ((warning . python-mypy)))
  10977 
  10978 (defun flycheck-pyright--parse-error (output checker buffer)
  10979   "Parse pyright errors/warnings from JSON OUTPUT.
  10980 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  10981 the BUFFER that was checked respectively."
  10982   (seq-map
  10983    (lambda (err)
  10984      (let-alist err
  10985        (flycheck-error-new-at
  10986         (+ 1 .range.start.line)
  10987         (+ 1 .range.start.character)
  10988         (pcase .severity
  10989           ("error" 'error)
  10990           ("warning" 'warning)
  10991           (_ 'warning))
  10992         .message
  10993         :end-line (+ 1 .range.end.line)
  10994         :end-column (+ 1 .range.end.character)
  10995         :checker checker
  10996         :buffer buffer
  10997         :filename (buffer-file-name buffer))))
  10998    (cdr (nth 2 (car (flycheck-parse-json output))))))
  10999 
  11000 (flycheck-define-checker python-pyright
  11001   "Static type checker for Python
  11002 
  11003 See URL https://github.com/microsoft/pyright."
  11004   :command ("pyright"
  11005             "--outputjson"
  11006             source-inplace)
  11007   :working-directory flycheck-python-find-project-root
  11008   :error-parser flycheck-pyright--parse-error
  11009   :modes (python-mode python-ts-mode))
  11010 
  11011 (define-obsolete-variable-alias 'flycheck-python-mypy-ini
  11012   'flycheck-python-mypy-config "32")
  11013 
  11014 (flycheck-def-config-file-var flycheck-python-mypy-config python-mypy
  11015                               '("mypy.ini" "pyproject.toml" "setup.cfg"))
  11016 
  11017 (flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy
  11018   "Directory used to write .mypy_cache directories."
  11019   :type '(choice
  11020           (const :tag "Write to the working directory" nil)
  11021           (const :tag "Never write .mypy_cache directories" null-device)
  11022           (string :tag "Path"))
  11023   :safe #'flycheck-string-or-nil-p
  11024   :package-version '(flycheck . "32"))
  11025 
  11026 (flycheck-def-option-var flycheck-python-mypy-python-executable nil python-mypy
  11027   "Python executable to find the installed PEP 561 packages."
  11028   :type '(choice (const :tag "Same as mypy's" nil)
  11029                  (string :tag "Path"))
  11030   :safe #'flycheck-string-or-nil-p
  11031   :package-version '(flycheck . "33"))
  11032 
  11033 (flycheck-define-checker python-mypy
  11034   "Mypy syntax and type checker.  Requires mypy>=0.730.
  11035 
  11036 See URL `https://mypy-lang.org/'."
  11037   :command ("mypy"
  11038             "--show-column-numbers"
  11039             "--no-pretty"
  11040             (config-file "--config-file" flycheck-python-mypy-config)
  11041             (option "--cache-dir" flycheck-python-mypy-cache-dir)
  11042             (option "--python-executable" flycheck-python-mypy-python-executable)
  11043             source-original)
  11044   :error-patterns
  11045   ((error line-start (file-name) ":" line (optional ":" column)
  11046           ": error:" (message) line-end)
  11047    (warning line-start (file-name) ":" line (optional ":" column)
  11048             ": warning:" (message) line-end)
  11049    (info line-start (file-name) ":" line (optional ":" column)
  11050          ": note:" (message) line-end))
  11051   :working-directory flycheck-python-find-project-root
  11052   :modes (python-mode python-ts-mode)
  11053   ;; Ensure the file is saved, to work around
  11054   ;; https://github.com/python/mypy/issues/4746.
  11055   :predicate flycheck-buffer-saved-p)
  11056 
  11057 (flycheck-def-option-var flycheck-lintr-caching t r-lintr
  11058   "Whether to enable caching in lintr.
  11059 
  11060 By default, lintr caches all expressions in a file and re-checks
  11061 only those that have changed.  Setting this option to nil
  11062 disables caching in case there are problems."
  11063   :type 'boolean
  11064   :safe #'booleanp
  11065   :package-version '(flycheck . "0.23"))
  11066 
  11067 (flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr
  11068   "Linters to use with lintr.
  11069 
  11070 The value of this variable is a string containing an R
  11071 expression, which selects linters for lintr."
  11072   :type 'string
  11073   :risky t
  11074   :package-version '(flycheck . "0.23"))
  11075 
  11076 (defun flycheck-r-has-lintr (checker)
  11077   "Whether CHECKER (R) has installed the `lintr' library."
  11078   (eql 0 (flycheck-call-checker-process
  11079           checker nil nil nil
  11080           "--slave" "--no-restore" "--no-save" "-e"
  11081           "library('lintr')")))
  11082 
  11083 (flycheck-define-checker r-lintr
  11084   "An R style and syntax checker using the lintr package.
  11085 
  11086 See URL `https://github.com/jimhester/lintr'."
  11087   :command ("R" "--slave" "--no-restore" "--no-save" "-e"
  11088             (eval (concat
  11089                    "library(lintr);"
  11090                    "try(lint(commandArgs(TRUE)"
  11091                    ", cache=" (if flycheck-lintr-caching "TRUE" "FALSE")
  11092                    ", " flycheck-lintr-linters
  11093                    "))"))
  11094             "--args" source)
  11095   :error-patterns
  11096   ((info line-start (file-name) ":" line ":" column ": style: " (message)
  11097          line-end)
  11098    (warning line-start (file-name) ":" line ":" column ": warning: " (message)
  11099             line-end)
  11100    (error line-start (file-name) ":" line ":" column ": error: " (message)
  11101           line-end))
  11102   :modes (ess-mode ess-r-mode)
  11103   :predicate
  11104   ;; Don't check ESS files which do not contain R, and make sure that lintr is
  11105   ;; actually available
  11106   (lambda ()
  11107     (and (equal ess-language "S")
  11108          (flycheck-r-has-lintr 'r-lintr)))
  11109   :verify (lambda (checker)
  11110             (let ((has-lintr (flycheck-r-has-lintr checker)))
  11111               (list
  11112                (flycheck-verification-result-new
  11113                 :label "lintr library"
  11114                 :message (if has-lintr "present" "missing")
  11115                 :face (if has-lintr 'success '(bold error)))))))
  11116 
  11117 (flycheck-define-checker r
  11118   "An R syntax checker using the builtin `parse' function.
  11119 
  11120 See URL: `https://www.r-project.org/'."
  11121   :command ("R" "--slave" "--no-restore" "--no-save" "-e"
  11122             "parse(file=file('stdin'), srcfile='<stdin>')")
  11123   :standard-input t
  11124   :error-patterns
  11125   ((error line-start (zero-or-more space) "<stdin>:" line ":" column ": "
  11126           (message) line-end))
  11127   :modes (ess-mode ess-r-mode)
  11128   :predicate
  11129   ;; Don't check ESS files which do not contain R
  11130   (lambda () (equal ess-language "S")))
  11131 
  11132 (defun flycheck-racket-has-expand-p (checker)
  11133   "Whether the executable of CHECKER provides the `expand' command."
  11134   (eql 0 (flycheck-call-checker-process checker nil nil nil "expand")))
  11135 
  11136 (flycheck-define-checker racket
  11137   "A Racket syntax checker with `raco expand'.
  11138 
  11139 The `compiler-lib' racket package is required for this syntax
  11140 checker.
  11141 
  11142 See URL `https://racket-lang.org/'."
  11143   :command ("raco" "expand" source-inplace)
  11144   :predicate
  11145   (lambda ()
  11146     (and (or (not (eq major-mode 'scheme-mode))
  11147              ;; In `scheme-mode' we must check the current Scheme implementation
  11148              ;; being used
  11149              (and (boundp 'geiser-impl--implementation)
  11150                   (eq geiser-impl--implementation 'racket)))
  11151          (flycheck-racket-has-expand-p 'racket)))
  11152   :verify
  11153   (lambda (checker)
  11154     (let ((has-expand (flycheck-racket-has-expand-p checker))
  11155           (in-scheme-mode (eq major-mode 'scheme-mode))
  11156           (geiser-impl (bound-and-true-p geiser-impl--implementation)))
  11157       (list
  11158        (flycheck-verification-result-new
  11159         :label "compiler-lib package"
  11160         :message (if has-expand "present" "missing")
  11161         :face (if has-expand 'success '(bold error)))
  11162        (flycheck-verification-result-new
  11163         :label "Geiser Implementation"
  11164         :message (cond
  11165                   ((not in-scheme-mode) "Using Racket Mode")
  11166                   ((eq geiser-impl 'racket) "Racket")
  11167                   (geiser-impl (format "Other: %s" geiser-impl))
  11168                   (t "Geiser not active"))
  11169         :face (cond
  11170                ((or (not in-scheme-mode) (eq geiser-impl 'racket)) 'success)
  11171                (t '(bold error)))))))
  11172   :error-filter
  11173   (lambda (errors)
  11174     (flycheck-sanitize-errors
  11175      (flycheck-increment-error-columns
  11176       (seq-remove
  11177        (lambda (err)
  11178          (string-suffix-p
  11179           "/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt"
  11180           (flycheck-error-filename err)))
  11181        errors))))
  11182   :error-patterns
  11183   ((error line-start (zero-or-more space)
  11184           (file-name) ":" line ":" column ":" (message) line-end))
  11185   :modes (racket-mode scheme-mode))
  11186 
  11187 (flycheck-define-checker rpm-rpmlint
  11188   "A RPM SPEC file syntax checker using rpmlint.
  11189 
  11190 See URL `https://github.com/rpm-software-management/rpmlint'."
  11191   :command ("rpmlint" source)
  11192   :error-patterns
  11193   ((error line-start
  11194           (file-name) ":" (optional line ":") " E: " (message)
  11195           line-end)
  11196    (warning line-start
  11197             (file-name) ":" (optional line ":") " W: " (message)
  11198             line-end))
  11199   :error-filter
  11200   ;; rpmlint 1.1 outputs a spurious error for the temp file created by flycheck
  11201   (lambda (errors)
  11202     (dolist (err (seq-remove
  11203                   (lambda (err)
  11204                     (string-suffix-p "(none)" (flycheck-error-filename err)))
  11205                   errors))
  11206       ;; Add fake line numbers if they are missing in the lint output
  11207       (unless (flycheck-error-line err)
  11208         (setf (flycheck-error-line err) 1)))
  11209     errors)
  11210   :error-explainer
  11211   (lambda (error)
  11212     (when-let* ((error-message (flycheck-error-message error))
  11213                 (message-id (save-match-data
  11214                               (string-match "\\([^ ]+\\)" error-message)
  11215                               (match-string 1 error-message))))
  11216       (flycheck-call-checker-process-for-output
  11217        'rpm-rpmlint nil t "-I" message-id)))
  11218   :modes (sh-mode rpm-spec-mode)
  11219   :predicate (lambda () (or (not (eq major-mode 'sh-mode))
  11220                             ;; In `sh-mode', we need the proper shell
  11221                             (eq sh-shell 'rpm))))
  11222 
  11223 (flycheck-def-config-file-var flycheck-markdown-markdownlint-cli-config
  11224     markdown-markdownlint-cli
  11225     '(".markdownlint.json" ".markdownlint.jsonc" ".markdownlint.yaml")
  11226   :package-version '(flycheck . "33"))
  11227 
  11228 (flycheck-def-option-var flycheck-markdown-markdownlint-cli-disable-rules
  11229     nil markdown-markdownlint-cli
  11230   "Rules to disable for markdownlint-cli."
  11231   :type '(repeat :tag "Disabled rule"
  11232                  (string :tag "Rule name"))
  11233   :safe #'flycheck-string-list-p
  11234   :package-version '(flycheck . "33"))
  11235 
  11236 (flycheck-def-option-var flycheck-markdown-markdownlint-cli-enable-rules
  11237     nil markdown-markdownlint-cli
  11238   "Rules to enable for markdownlint-cli."
  11239   :type '(repeat :tag "Enabled rule"
  11240                  (string :tag "Rule name"))
  11241   :safe #'flycheck-string-list-p
  11242   :package-version '(flycheck . "33"))
  11243 
  11244 (flycheck-define-checker markdown-markdownlint-cli
  11245   "Markdown checker using markdownlint-cli.
  11246 
  11247 See URL `https://github.com/igorshubovych/markdownlint-cli'."
  11248   :command ("markdownlint"
  11249             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
  11250             (option-list "--disable" flycheck-markdown-markdownlint-cli-disable-rules)
  11251             (option-list "--enable" flycheck-markdown-markdownlint-cli-enable-rules)
  11252             "--"
  11253             source)
  11254   :error-patterns
  11255   ((error line-start
  11256           (file-name) ":" line
  11257           (? ":" column) " " (id (one-or-more (not (any space))))
  11258           " " (message) line-end))
  11259   :error-filter
  11260   (lambda (errors)
  11261     (flycheck-sanitize-errors
  11262      (flycheck-remove-error-file-names "(string)" errors)))
  11263   :modes (markdown-mode gfm-mode)
  11264   :error-explainer
  11265   (lambda (err)
  11266     (let ((error-code (substring (flycheck-error-id err) 0 5))
  11267           (url "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#%s"))
  11268       (and error-code `(url . ,(format url error-code))))))
  11269 
  11270 (flycheck-def-option-var flycheck-markdown-mdl-rules nil markdown-mdl
  11271   "Rules to enable for mdl.
  11272 
  11273 The value of this variable is a list of strings each of which is
  11274 the name of a rule to enable.
  11275 
  11276 By default all rules are enabled.
  11277 
  11278 See URL `https://git.io/vhi2t'."
  11279   :type '(repeat :tag "Enabled rules"
  11280                  (string :tag "rule name"))
  11281   :safe #'flycheck-string-list-p
  11282   :package-version '(flycheck . "27"))
  11283 
  11284 (flycheck-def-option-var flycheck-markdown-mdl-tags nil markdown-mdl
  11285   "Rule tags to enable for mdl.
  11286 
  11287 The value of this variable is a list of strings each of which is
  11288 the name of a rule tag.  Only rules with these tags are enabled.
  11289 
  11290 By default all rules are enabled.
  11291 
  11292 See URL `https://git.io/vhi2t'."
  11293   :type '(repeat :tag "Enabled tags"
  11294                  (string :tag "tag name"))
  11295   :safe #'flycheck-string-list-p
  11296   :package-version '(flycheck . "27"))
  11297 
  11298 (flycheck-def-config-file-var flycheck-markdown-mdl-style markdown-mdl nil
  11299   :package-version '(flycheck . "27"))
  11300 
  11301 (flycheck-define-checker markdown-mdl
  11302   "Markdown checker using mdl.
  11303 
  11304 See URL `https://github.com/markdownlint/markdownlint'."
  11305   :command ("mdl"
  11306             (config-file "--style" flycheck-markdown-mdl-style)
  11307             (option "--tags=" flycheck-markdown-mdl-tags concat
  11308                     flycheck-option-comma-separated-list)
  11309             (option "--rules=" flycheck-markdown-mdl-rules concat
  11310                     flycheck-option-comma-separated-list))
  11311   :standard-input t
  11312   :error-patterns
  11313   ((error line-start
  11314           (file-name) ":" line ": " (id (one-or-more alnum)) " " (message)
  11315           line-end))
  11316   :error-filter
  11317   (lambda (errors)
  11318     (flycheck-sanitize-errors
  11319      (flycheck-remove-error-file-names "(stdin)" errors)))
  11320   :modes (markdown-mode gfm-mode))
  11321 
  11322 (flycheck-def-config-file-var flycheck-markdown-pymarkdown-config
  11323     markdown-pymarkdown nil
  11324   :package-version '(flycheck . "34"))
  11325 
  11326 (flycheck-define-checker markdown-pymarkdown
  11327   "Markdown checker using PyMarkdown.
  11328 
  11329 See URL `https://pypi.org/project/pymarkdownlnt/'."
  11330   :command ("pymarkdown"
  11331             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
  11332             "scan"
  11333             source)
  11334   :error-patterns
  11335   ((error line-start
  11336           (file-name) ":" line
  11337           (? ":" column) ": " (id (one-or-more alnum))
  11338           ": " (message) line-end))
  11339   :error-filter
  11340   (lambda (errors)
  11341     (flycheck-sanitize-errors
  11342      (flycheck-remove-error-file-names "(string)" errors)))
  11343   :modes (markdown-mode gfm-mode))
  11344 
  11345 (flycheck-define-checker nix
  11346   "Nix checker using nix-instantiate.
  11347 
  11348 See URL `https://nixos.org/nix/manual/#sec-nix-instantiate'."
  11349   :command ("nix-instantiate" "--parse" "-")
  11350   :standard-input t
  11351   :error-patterns
  11352   ((error line-start
  11353           "error: " (message)
  11354           (one-or-more "\n")
  11355           (zero-or-more space) "at «stdin»:" line ":" column ":" line-end)
  11356    (error line-start
  11357           "at: (" line ":" column ") from stdin"
  11358           (one-or-more "\n" (zero-or-more space (one-or-more not-newline)))
  11359           (message) line-end)
  11360    (error line-start
  11361           "error: " (message) " at " (file-name) ":" line ":" column
  11362           line-end))
  11363   :error-filter
  11364   (lambda (errors)
  11365     (flycheck-sanitize-errors
  11366      (flycheck-remove-error-file-names "(string)" errors)))
  11367   :next-checkers ((warning . nix-linter))
  11368   :modes (nix-mode nix-ts-mode))
  11369 
  11370 (defun flycheck-parse-nix-linter (output checker buffer)
  11371   "Parse nix-linter warnings from JSON OUTPUT.
  11372 
  11373 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  11374 the BUFFER that was checked respectively.
  11375 
  11376 See URL `https://github.com/Synthetica9/nix-linter' for more
  11377 information about nix-linter."
  11378   (mapcar (lambda (err)
  11379             (let-alist err
  11380               (flycheck-error-new-at
  11381                .pos.spanBegin.sourceLine
  11382                .pos.spanBegin.sourceColumn
  11383                'warning
  11384                .description
  11385                :id .offense
  11386                :checker checker
  11387                :buffer buffer
  11388                :filename (buffer-file-name buffer)
  11389                :end-line .pos.spanEnd.sourceLine
  11390                :end-column .pos.spanEnd.sourceColumn)))
  11391           (flycheck-parse-json output)))
  11392 
  11393 (flycheck-define-checker nix-linter
  11394   "Nix checker using nix-linter.
  11395 
  11396 See URL `https://github.com/Synthetica9/nix-linter'."
  11397   :command ("nix-linter" "--json-stream" "-")
  11398   :standard-input t
  11399   :error-parser flycheck-parse-nix-linter
  11400   :error-explainer
  11401   (lambda (error)
  11402     (when-let (error-code (flycheck-error-id error))
  11403       (flycheck-call-checker-process-for-output
  11404        'nix-linter nil t "--help-for" error-code)))
  11405   :modes (nix-mode nix-ts-mode))
  11406 
  11407 (defun flycheck-parse-statix (output checker buffer)
  11408   "Parse statix warnings from JSON OUTPUT.
  11409 
  11410 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  11411 the BUFFER that was checked respectively.
  11412 
  11413 See URL `https://github.com/nerdypepper/statix' for more
  11414 information about statix."
  11415   (mapcar (lambda (err)
  11416             ;; Diagnostic information is a (seemingly always) 1 element array.
  11417             (let-alist (car (alist-get 'diagnostics err))
  11418               (let ((message .message)
  11419                     (start-line .at.from.line)
  11420                     (start-column .at.from.column)
  11421                     (end-line .at.to.line)
  11422                     (end-column .at.to.column))
  11423 
  11424                 (let-alist err
  11425                   (flycheck-error-new-at
  11426                    start-line
  11427                    start-column
  11428                    (pcase .severity ("Error" 'error)
  11429                           ("Warn" 'warning)
  11430                           (_ 'warning))
  11431                    (format "%s: %s" .note message)
  11432                    :id (format "%s%02d" (pcase .severity
  11433                                           ("Error" "E")
  11434                                           ("Warn" "W")
  11435                                           (_ "")) .code)
  11436                    :checker checker
  11437                    :buffer buffer
  11438                    :filename (buffer-file-name buffer)
  11439                    :end-line end-line
  11440                    :end-column end-column)))))
  11441           (alist-get 'report (car (flycheck-parse-json output)))))
  11442 
  11443 (flycheck-define-checker statix
  11444   "Nix checker using statix.
  11445 
  11446 See URL `https://github.com/nerdypepper/statix'."
  11447   :command ("statix" "check" "-o=json" source)
  11448   :error-parser flycheck-parse-statix
  11449   :modes nix-mode)
  11450 
  11451 (defun flycheck-locate-sphinx-source-directory ()
  11452   "Locate the Sphinx source directory for the current buffer.
  11453 
  11454 Return the source directory, or nil, if the current buffer is not
  11455 part of a Sphinx project."
  11456   (when-let* ((filename (buffer-file-name))
  11457               (dir (locate-dominating-file filename "conf.py")))
  11458     (expand-file-name dir)))
  11459 
  11460 (flycheck-define-checker rst
  11461   "A ReStructuredText (RST) syntax checker using Docutils.
  11462 
  11463 See URL `https://docutils.sourceforge.net/'."
  11464   ;; include:: directives
  11465   :command ("rst2pseudoxml.py" "--report=2" "--halt=5"
  11466             ;; Read from standard input and throw output away
  11467             "-" null-device)
  11468   :standard-input t
  11469   :error-patterns
  11470   ((warning line-start "<stdin>:" line ": (WARNING/2) " (message) line-end)
  11471    (error line-start "<stdin>:" line
  11472           ": (" (or "ERROR/3" "SEVERE/4") ") "
  11473           (message) line-end))
  11474   :modes rst-mode)
  11475 
  11476 (flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx
  11477   "Whether to warn about missing references in Sphinx.
  11478 
  11479 When non-nil (the default), warn about all missing references in
  11480 Sphinx via `-n'."
  11481   :type 'boolean
  11482   :safe #'booleanp
  11483   :package-version '(flycheck . "0.17"))
  11484 
  11485 (flycheck-define-checker rst-sphinx
  11486   "A ReStructuredText (RST) syntax checker using Sphinx.
  11487 
  11488 Requires Sphinx 1.2 or newer.  See URL `https://sphinx-doc.org'."
  11489   :command ("sphinx-build" "-b" "pseudoxml"
  11490             "-q" "-N"                   ; Reduced output and no colors
  11491             (option-flag "-n" flycheck-sphinx-warn-on-missing-references)
  11492             (eval (flycheck-locate-sphinx-source-directory))
  11493             temporary-directory         ; Redirect the output to a temporary
  11494                                         ; directory
  11495             source-original)            ; Sphinx needs the original document
  11496   :error-patterns
  11497   ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end)
  11498    (error line-start
  11499           (file-name) ":" line
  11500           ": " (or "ERROR" "SEVERE") ": "
  11501           (message) line-end))
  11502   :modes rst-mode
  11503   :predicate (lambda () (and (flycheck-buffer-saved-p)
  11504                              (flycheck-locate-sphinx-source-directory))))
  11505 
  11506 (defun flycheck-ruby--find-project-root (_checker)
  11507   "Compute an appropriate working-directory for flycheck-ruby.
  11508 
  11509 This is either a parent directory containing a Gemfile, or nil."
  11510   (and
  11511    buffer-file-name
  11512    (locate-dominating-file buffer-file-name "Gemfile")))
  11513 
  11514 (defun flycheck-ruby--filter-rubocop-errors (errors)
  11515   "Filter RuboCop ERRORS attributed to dummy stdin filename."
  11516   (flycheck-remove-error-file-names
  11517    (flycheck--file-truename (expand-file-name "stdin"))
  11518    errors))
  11519 
  11520 (flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml")
  11521 
  11522 (flycheck-def-option-var flycheck-rubocop-lint-only nil
  11523                          (ruby-rubocop ruby-standard ruby-chef-cookstyle)
  11524   "Whether to only report code issues in Rubocop, Cookstyle and Standard.
  11525 
  11526 When non-nil, only report code issues, via `--lint'.  Otherwise
  11527 report style issues as well."
  11528   :safe #'booleanp
  11529   :type 'boolean
  11530   :package-version '(flycheck . "0.16"))
  11531 
  11532 (defconst flycheck-ruby-rubocop-error-patterns
  11533   '((info line-start (file-name) ":" line ":" column ": C: "
  11534           (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
  11535     (warning line-start (file-name) ":" line ":" column ": W: "
  11536              (optional (id (one-or-more (not (any ":")))) ": ") (message)
  11537              line-end)
  11538     (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
  11539            (optional (id (one-or-more (not (any ":")))) ": ") (message)
  11540            line-end)))
  11541 
  11542 (flycheck-def-executable-var ruby-rubocop "rubocop")
  11543 (flycheck-define-command-checker 'ruby-rubocop
  11544   "A Ruby syntax and style checker using the RuboCop tool.
  11545 
  11546 You need at least RuboCop 0.34 for this syntax checker.
  11547 
  11548 See URL `https://rubocop.org/'."
  11549   ;; ruby-standard is defined based on this checker
  11550   :command '("rubocop"
  11551              "--display-cop-names"
  11552              "--force-exclusion"
  11553              "--format" "emacs"
  11554              (config-file "--config" flycheck-rubocoprc)
  11555              (option-flag "--lint" flycheck-rubocop-lint-only)
  11556              ;; RuboCop takes the original file name as argument when reading
  11557              ;; from standard input, but it chokes when that name is the empty
  11558              ;; string, so fall back to "stdin" in order to handle buffers with
  11559              ;; no backing file (e.g. org-mode snippet buffers)
  11560              "--stdin" (eval (or (buffer-file-name) "stdin")))
  11561   :standard-input t
  11562   :working-directory #'flycheck-ruby--find-project-root
  11563   :error-patterns flycheck-ruby-rubocop-error-patterns
  11564   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11565   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11566   :next-checkers '((warning . ruby-reek)
  11567                    (warning . ruby-chef-cookstyle)))
  11568 
  11569 (flycheck-def-executable-var ruby-chef-cookstyle "cookstyle")
  11570 (flycheck-define-command-checker 'ruby-chef-cookstyle
  11571   "A Chef (Ruby) syntax and style checker using the Cookstyle tool.
  11572 Basically Cookstyle is a thin wrapper around RuboCop, so this
  11573 checker is essentially the same.
  11574 
  11575 See URL `https://github.com/chef/cookstyle'."
  11576   :command '("cookstyle"
  11577              "--display-cop-names"
  11578              "--force-exclusion"
  11579              "--format" "emacs"
  11580              (config-file "--config" flycheck-rubocoprc)
  11581              (option-flag "--lint" flycheck-rubocop-lint-only)
  11582              ;; RuboCop takes the original file name as argument when reading
  11583              ;; from standard input, but it chokes when that name is the empty
  11584              ;; string, so fall back to "stdin" in order to handle buffers with
  11585              ;; no backing file (e.g. org-mode snippet buffers)
  11586              "--stdin" (eval (or (buffer-file-name) "stdin")))
  11587   :standard-input t
  11588   :working-directory #'flycheck-ruby--find-project-root
  11589   :error-patterns flycheck-ruby-rubocop-error-patterns
  11590   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11591   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11592   :predicate
  11593   (lambda ()
  11594     (let ((parent-dir (file-name-directory
  11595                        (directory-file-name
  11596                         (expand-file-name default-directory)))))
  11597       (or
  11598        ;; Chef CookBook
  11599        ;; https://docs.opscode.com/chef/knife.html#id38
  11600        (locate-dominating-file parent-dir "recipes")
  11601        ;; Knife Solo
  11602        ;; https://matschaffer.github.io/knife-solo/#label-Init+command
  11603        (locate-dominating-file parent-dir "cookbooks"))))
  11604   :next-checkers '((warning . ruby-reek)))
  11605 
  11606 (flycheck-def-config-file-var flycheck-ruby-standardrc ruby-standard
  11607                               ".standard.yml")
  11608 
  11609 (flycheck-def-executable-var ruby-standard "standardrb")
  11610 (flycheck-define-command-checker 'ruby-standard
  11611   "A Ruby syntax and style checker using the StandardRB gem.
  11612 
  11613 See URL `https://github.com/testdouble/standard' for more information."
  11614   ;; This checker is derived from ruby-rubocop; see above
  11615   :command '("standardrb"
  11616              "--display-cop-names"
  11617              "--force-exclusion"
  11618              "--format" "emacs"
  11619              "--cache" "false"
  11620              (config-file "--config" flycheck-ruby-standardrc)
  11621              (option-flag "--lint" flycheck-rubocop-lint-only)
  11622              "--stdin" source-original)
  11623   :standard-input t
  11624   :working-directory #'flycheck-ruby--find-project-root
  11625   :error-patterns flycheck-ruby-rubocop-error-patterns
  11626   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11627   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11628   :next-checkers '((warning . ruby-reek)
  11629                    (warning . ruby-chef-cookstyle)))
  11630 
  11631 (flycheck-def-config-file-var flycheck-reekrc ruby-reek ".reek.yml"
  11632   :safe #'string-or-null-p
  11633   :package-version '(flycheck . "30"))
  11634 
  11635 (flycheck-define-checker ruby-reek
  11636   "A Ruby smell checker using reek.
  11637 
  11638 See URL `https://github.com/troessner/reek'."
  11639   :command ("reek" "--format" "json"
  11640             (config-file "--config" flycheck-reekrc)
  11641             source)
  11642   :error-parser flycheck-parse-reek
  11643   :modes (enh-ruby-mode ruby-mode ruby-ts-mode))
  11644 
  11645 (flycheck-define-checker ruby
  11646   "A Ruby syntax checker using the standard Ruby interpreter.
  11647 
  11648 Please note that the output of different Ruby versions and
  11649 implementations varies wildly.  This syntax checker supports
  11650 current versions of MRI and JRuby, but may break when used with
  11651 other implementations or future versions of these
  11652 implementations.
  11653 
  11654 Please consider using `ruby-rubocop' or `ruby-reek' instead.
  11655 
  11656 See URL `https://www.ruby-lang.org/'."
  11657   :command ("ruby" "-w" "-c")
  11658   :standard-input t
  11659   :error-patterns
  11660   ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv
  11661   ((error line-start "SyntaxError in -:" line ": " (message) line-end)
  11662    (warning line-start "-:" line ":" (optional column ":")
  11663             " warning: " (message) line-end)
  11664    (error line-start "-:" line ": " (message) line-end))
  11665   :modes (enh-ruby-mode ruby-mode ruby-ts-mode)
  11666   :next-checkers ((warning . ruby-chef-cookstyle)))
  11667 
  11668 (flycheck-define-checker ruby-jruby
  11669   "A Ruby syntax checker using the JRuby interpreter.
  11670 
  11671 This syntax checker is very primitive, and may break on future
  11672 versions of JRuby.
  11673 
  11674 Please consider using `ruby-rubocop' instead.
  11675 
  11676 See URL `https://jruby.org/'."
  11677   :command ("jruby" "-w" "-c")
  11678   :standard-input t
  11679   :error-patterns
  11680   ((error   line-start "SyntaxError in -:" line ": " (message) line-end)
  11681    (warning line-start "-:" line ": warning: " (message) line-end)
  11682    (error   line-start "-:" line ": "          (message) line-end))
  11683   :modes (enh-ruby-mode ruby-mode ruby-ts-mode))
  11684 
  11685 (flycheck-def-args-var flycheck-cargo-check-args (rust-cargo)
  11686   :package-version '(flycheck . "32"))
  11687 
  11688 (flycheck-def-args-var flycheck-rust-args (rust)
  11689   :package-version '(flycheck . "0.24"))
  11690 
  11691 (flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust)
  11692   "Whether to check test code in Rust.
  11693 
  11694 For the `rust' checker: When non-nil, `rustc' is passed the
  11695 `--test' flag, which will check any code marked with the
  11696 `#[cfg(test)]' attribute and any functions marked with
  11697 `#[test]'. Otherwise, `rustc' is not passed `--test' and test
  11698 code will not be checked.  Skipping `--test' is necessary when
  11699 using `#![no_std]', because compiling the test runner requires
  11700 `std'.
  11701 
  11702 For the `rust-cargo' checker: When non-nil, calls `cargo test
  11703 --no-run' instead of `cargo check'."
  11704   :type 'boolean
  11705   :safe #'booleanp
  11706   :package-version '("flycheck" . "0.19"))
  11707 
  11708 (flycheck-def-option-var flycheck-rust-crate-root nil rust
  11709   "A path to the crate root for the current buffer.
  11710 
  11711 The value of this variable is either a string with the path to
  11712 the crate root for the current buffer, or nil if the current buffer
  11713 is a crate.  A relative path is relative to the current buffer.
  11714 
  11715 If this variable is non nil the current buffer will only be checked
  11716 if it is not modified, i.e. after it has been saved."
  11717   :type '(choice (const :tag "Unspecified" nil)
  11718                  (file :tag "Root"))
  11719   :safe #'flycheck-string-or-nil-p
  11720   :package-version '(flycheck . "0.20"))
  11721 (make-variable-buffer-local 'flycheck-rust-crate-root)
  11722 
  11723 (flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust)
  11724   "The type of the Rust Crate to check.
  11725 
  11726 For `rust-cargo', the value should be a string denoting the
  11727 target type passed to Cargo.  See
  11728 `flycheck-rust-valid-crate-type-p' for the list of allowed
  11729 values.
  11730 
  11731 For `rust', the value should be a string denoting the crate type
  11732 for the `--crate-type' flag of rustc."
  11733   :type '(choice (const :tag "nil (rust/rust-cargo)" nil)
  11734                  (const :tag "lib (rust/rust-cargo)" "lib")
  11735                  (const :tag "bin (rust/rust-cargo)" "bin")
  11736                  (const :tag "example (rust-cargo)" "example")
  11737                  (const :tag "test (rust-cargo)" "test")
  11738                  (const :tag "bench (rust-cargo)" "bench")
  11739                  (const :tag "rlib (rust)" "rlib")
  11740                  (const :tag "dylib (rust)" "dylib")
  11741                  (const :tag "cdylib (rust)" "cdylib")
  11742                  (const :tag "staticlib (rust)" "staticlib")
  11743                  (const :tag "metadata (rust)" "metadata"))
  11744   :safe #'stringp
  11745   :package-version '(flycheck . "0.20"))
  11746 (make-variable-buffer-local 'flycheck-rust-crate-type)
  11747 
  11748 (flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo
  11749   "The name of the binary to pass to `cargo check --CRATE-TYPE'.
  11750 
  11751 The value of this variable is a string denoting the name of the
  11752 target to check: usually the name of the crate, or the name of
  11753 one of the files under `src/bin', `tests', `examples' or
  11754 `benches'.
  11755 
  11756 This always requires a non-nil value, unless
  11757 `flycheck-rust-crate-type' is `lib' or nil, in which case it is
  11758 ignored."
  11759   :type '(choice (const :tag "Unspecified" nil)
  11760                  (string :tag "Binary name"))
  11761   :safe #'flycheck-string-or-nil-p
  11762   :package-version '(flycheck . "28"))
  11763 (make-variable-buffer-local 'flycheck-rust-binary-name)
  11764 
  11765 (flycheck-def-option-var flycheck-rust-features nil rust-cargo
  11766   "List of features to activate during build or check.
  11767 
  11768 The value of this variable is a list of strings denoting features
  11769 that will be activated to build the target to check. Features will
  11770 be passed to `cargo check --features=FEATURES'."
  11771   :type '(repeat :tag "Features to activate"
  11772                  (string :tag "Feature"))
  11773   :safe #'flycheck-string-list-p
  11774   :package-version '(flycheck . "32"))
  11775 (make-variable-buffer-local 'flycheck-rust-features)
  11776 
  11777 (flycheck-def-option-var flycheck-rust-library-path nil rust
  11778   "A list of library directories for Rust.
  11779 
  11780 The value of this variable is a list of strings, where each
  11781 string is a directory to add to the library path of Rust.
  11782 Relative paths are relative to the file being checked."
  11783   :type '(repeat (directory :tag "Library directory"))
  11784   :safe #'flycheck-string-list-p
  11785   :package-version '(flycheck . "0.18"))
  11786 
  11787 (defun flycheck--fontify-as-markdown ()
  11788   "Place current buffer in `markdown-view-mode' and fontify it."
  11789   (when (fboundp 'markdown-view-mode)
  11790     (let ((markdown-fontify-code-block-default-mode 'rust-mode)
  11791           (markdown-fontify-code-blocks-natively t)
  11792           (markdown-hide-markup t))
  11793       (markdown-view-mode)
  11794       (font-lock-flush)
  11795       (font-lock-ensure))))
  11796 
  11797 (defun flycheck-rust-error-explainer (error)
  11798   "Return an explanation for the given `flycheck-error' ERROR."
  11799   (when-let (error-code (flycheck-error-id error))
  11800     (lambda ()
  11801       (flycheck-call-checker-process
  11802        'rust nil standard-output t "--explain" error-code)
  11803       (with-current-buffer standard-output
  11804         (flycheck--fontify-as-markdown)))))
  11805 
  11806 (defun flycheck-rust-error-filter (errors)
  11807   "Filter ERRORS from rustc output that have no explanatory value."
  11808   (seq-remove
  11809    (lambda (err)
  11810      (or
  11811       ;; Macro errors emit a diagnostic in a phony file,
  11812       ;; e.g. "<println macros>".
  11813       (when-let (filename (flycheck-error-filename err))
  11814         (string-match-p (rx "macros>" line-end) filename))
  11815       ;; Redundant message giving the number of failed errors
  11816       (when-let (msg (flycheck-error-message err))
  11817         (string-match-p
  11818          (rx
  11819           (or (: "aborting due to " (optional (one-or-more num) " ")
  11820                  "previous error")
  11821               (: "For more information about this error, try `rustc --explain "
  11822                  (one-or-more alnum) "`.")))
  11823          msg))))
  11824    errors))
  11825 
  11826 (defun flycheck-rust-manifest-directory ()
  11827   "Return the nearest directory holding the Cargo manifest.
  11828 
  11829 Return the nearest directory containing the `Cargo.toml' manifest
  11830 file, starting from the current buffer and using
  11831 `locate-dominating-file'.  Return nil if there is no such file,
  11832 or if the current buffer has no file name."
  11833   (and buffer-file-name
  11834        (locate-dominating-file buffer-file-name "Cargo.toml")))
  11835 
  11836 (defun flycheck-rust-cargo-metadata ()
  11837   "Run `cargo metadata' and return the result as parsed JSON object."
  11838   (car (flycheck-parse-json
  11839         (flycheck-call-checker-process-for-output
  11840          'rust-cargo nil t
  11841          "metadata" "--no-deps" "--format-version" "1"))))
  11842 
  11843 (defun flycheck-rust-cargo-workspace-root ()
  11844   "Return the path to the workspace root of a Rust Cargo project.
  11845 
  11846 Return nil if the workspace root does not exist (for Rust
  11847 versions inferior to 1.25)."
  11848   (let-alist (flycheck-rust-cargo-metadata)
  11849     .workspace_root))
  11850 
  11851 (defun flycheck-rust-cargo-has-command-p (command)
  11852   "Whether Cargo has COMMAND in its list of commands.
  11853 
  11854 Execute `cargo --list' to find out whether COMMAND is present."
  11855   (let ((cargo (funcall flycheck-executable-find "cargo")))
  11856     (member command
  11857             (mapcar (lambda (line)
  11858                       (replace-regexp-in-string "\\s-*\\(\\S-+\\).*\\'" "\\1" line))
  11859                     (ignore-errors (process-lines cargo "--list"))))))
  11860 
  11861 (defun flycheck-rust-valid-crate-type-p (crate-type)
  11862   "Whether CRATE-TYPE is a valid target type for Cargo.
  11863 
  11864 A valid Cargo target type is one of `lib', `bin', `example',
  11865 `test' or `bench'."
  11866   (member crate-type '(nil "lib" "bin" "example" "test" "bench")))
  11867 
  11868 (flycheck-define-checker rust-cargo
  11869   "A Rust syntax checker using Cargo.
  11870 
  11871 This syntax checker requires Rust 1.17 or newer.  See URL
  11872 `https://www.rust-lang.org'."
  11873   :command ("cargo"
  11874             (eval (if flycheck-rust-check-tests
  11875                       "test"
  11876                     "check"))
  11877             (eval (when flycheck-rust-check-tests
  11878                     "--no-run"))
  11879             (eval (when flycheck-rust-crate-type
  11880                     (concat "--" flycheck-rust-crate-type)))
  11881             ;; All crate targets except "lib" need a binary name
  11882             (eval (when (and flycheck-rust-crate-type
  11883                              (not (string= flycheck-rust-crate-type "lib")))
  11884                     flycheck-rust-binary-name))
  11885             (option "--features=" flycheck-rust-features concat
  11886                     flycheck-option-comma-separated-list)
  11887             (eval flycheck-cargo-check-args)
  11888             "--message-format=json")
  11889   :error-parser flycheck-parse-cargo-rustc
  11890   :error-filter (lambda (errors)
  11891                   ;; In Rust 1.25+, filenames are relative to the workspace
  11892                   ;; root.
  11893                   (let ((root (flycheck-rust-cargo-workspace-root)))
  11894                     (seq-do (lambda (err)
  11895                               ;; Some errors are crate level and do not have a
  11896                               ;; filename
  11897                               (when (flycheck-error-filename err)
  11898                                 (setf (flycheck-error-filename err)
  11899                                       (expand-file-name
  11900                                        (flycheck-error-filename err) root))))
  11901                             (flycheck-rust-error-filter errors))))
  11902   :error-explainer flycheck-rust-error-explainer
  11903   :modes (rust-mode rust-ts-mode)
  11904   :predicate flycheck-buffer-saved-p
  11905   :enabled flycheck-rust-manifest-directory
  11906   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
  11907   :verify
  11908   (lambda (_)
  11909     (and buffer-file-name
  11910          (let* ((has-toml (flycheck-rust-manifest-directory))
  11911                 (valid-crate-type (flycheck-rust-valid-crate-type-p
  11912                                    flycheck-rust-crate-type))
  11913                 (need-binary-name
  11914                  (and flycheck-rust-crate-type
  11915                       (not (string= flycheck-rust-crate-type "lib")))))
  11916            (list
  11917             (flycheck-verification-result-new
  11918              :label "Cargo.toml"
  11919              :message (if has-toml "Found" "Missing")
  11920              :face (if has-toml 'success '(bold warning)))
  11921             (flycheck-verification-result-new
  11922              :label "Crate type"
  11923              :message (if valid-crate-type
  11924                           (format "%s" flycheck-rust-crate-type)
  11925                         (format "%s (invalid, should be one of 'lib', 'bin', \
  11926 'test', 'example' or 'bench')"
  11927                                 flycheck-rust-crate-type))
  11928              :face (if valid-crate-type 'success '(bold error)))
  11929             (flycheck-verification-result-new
  11930              :label "Binary name"
  11931              :message (cond
  11932                        ((not need-binary-name) "Not required")
  11933                        ((not flycheck-rust-binary-name) "Required")
  11934                        (t (format "%s" flycheck-rust-binary-name)))
  11935              :face (cond
  11936                     ((not need-binary-name) 'success)
  11937                     ((not flycheck-rust-binary-name) '(bold error))
  11938                     (t 'success))))))))
  11939 
  11940 (flycheck-define-checker rust
  11941   "A Rust syntax checker using Rust compiler.
  11942 
  11943 This syntax checker needs Rust 1.18 or newer.  See URL
  11944 `https://www.rust-lang.org'."
  11945   :command ("rustc"
  11946             (option "--crate-type" flycheck-rust-crate-type)
  11947             "--emit=mir" "-o" "/dev/null" ; avoid creating binaries
  11948             "--error-format=json"
  11949             (option-flag "--test" flycheck-rust-check-tests)
  11950             (option-list "-L" flycheck-rust-library-path concat)
  11951             (eval flycheck-rust-args)
  11952             (eval (or flycheck-rust-crate-root
  11953                       (flycheck-substitute-argument 'source-original 'rust))))
  11954   :error-parser flycheck-parse-rustc
  11955   :error-filter flycheck-rust-error-filter
  11956   :error-explainer flycheck-rust-error-explainer
  11957   :modes (rust-mode rust-ts-mode)
  11958   :predicate flycheck-buffer-saved-p)
  11959 
  11960 (flycheck-define-checker rust-clippy
  11961   "A Rust syntax checker using clippy.
  11962 
  11963 See URL `https://github.com/rust-lang-nursery/rust-clippy'."
  11964   :command ("cargo" "clippy" "--message-format=json")
  11965   :error-parser flycheck-parse-cargo-rustc
  11966   :error-filter flycheck-rust-error-filter
  11967   :error-explainer flycheck-rust-error-explainer
  11968   :modes (rust-mode rust-ts-mode)
  11969   :predicate flycheck-buffer-saved-p
  11970   :enabled (lambda ()
  11971              (and (flycheck-rust-cargo-has-command-p "clippy")
  11972                   (flycheck-rust-manifest-directory)))
  11973   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
  11974   :verify
  11975   (lambda (_)
  11976     (and buffer-file-name
  11977          (let ((has-toml (flycheck-rust-manifest-directory))
  11978                (has-clippy (flycheck-rust-cargo-has-command-p "clippy")))
  11979            (list
  11980             (flycheck-verification-result-new
  11981              :label "Clippy"
  11982              :message (if has-clippy "Found"
  11983                         "Cannot find the `cargo clippy' command")
  11984              :face (if has-clippy 'success '(bold warning)))
  11985             (flycheck-verification-result-new
  11986              :label "Cargo.toml"
  11987              :message (if has-toml "Found" "Missing")
  11988              :face (if has-toml 'success '(bold warning))))))))
  11989 
  11990 (flycheck-define-checker salt-lint
  11991   "A salt linter which apply common best practices for SaltStack.
  11992 
  11993 See URL `https://salt-lint.readthedocs.io/en/latest/'."
  11994   :command ("python" "-m" "saltlint" "--json")
  11995   :standard-input t
  11996   :error-parser flycheck-salt-lint-parser
  11997   :error-filter (lambda (errors) (flycheck-sanitize-errors errors))
  11998   :modes salt-mode)
  11999 
  12000 (defun flycheck-salt-lint-parser (output checker buffer)
  12001   "Parse salt lint JSON errors from OUTPUT.
  12002 
  12003 The arguments CHECKER and BUFFER are only passed through."
  12004   (condition-case nil
  12005       (let* ((json-array-type 'list)
  12006              (json-object-type 'plist)
  12007             (filename (buffer-file-name buffer))
  12008             (errors (json-read-from-string output)))
  12009         (mapcar (lambda (e)
  12010                   (flycheck-error-new
  12011                    :checker checker
  12012                    :buffer buffer
  12013                    :filename filename
  12014                    :level (pcase (plist-get e :severity)
  12015                             ("HIGH" 'error)
  12016                             ("MEDIUM" 'warning)
  12017                             ("LOW" 'warning)
  12018                             ("INFO" 'info)
  12019                             (_ 'info))
  12020                    :line (plist-get e :linenumber)
  12021                    :column 0
  12022                    :message (concat (plist-get e :message) (plist-get e :line))
  12023                    :id (plist-get e :id))) errors))
  12024     (json-error nil)))
  12025 
  12026 (defvar flycheck-sass-scss-cache-directory nil
  12027   "The cache directory for `sass' and `scss'.")
  12028 
  12029 (defun flycheck-sass-scss-cache-location ()
  12030   "Get the cache location for `sass' and `scss'.
  12031 
  12032 If no cache directory exists yet, create one and return it.
  12033 Otherwise return the previously used cache directory."
  12034   (setq flycheck-sass-scss-cache-directory
  12035         (or flycheck-sass-scss-cache-directory
  12036             (make-temp-file "flycheck-sass-scss-cache" 'directory))))
  12037 
  12038 (flycheck-def-option-var flycheck-sass-compass nil sass
  12039   "Whether to enable the Compass CSS framework.
  12040 
  12041 When non-nil, enable the Compass CSS framework, via `--compass'."
  12042   :type 'boolean
  12043   :safe #'booleanp
  12044   :package-version '(flycheck . "0.16"))
  12045 
  12046 (flycheck-define-checker sass
  12047   "A Sass syntax checker using the Sass compiler.
  12048 
  12049 See URL `https://sass-lang.com'."
  12050   :command ("sass"
  12051             "--cache-location" (eval (flycheck-sass-scss-cache-location))
  12052             (option-flag "--compass" flycheck-sass-compass)
  12053             "--check" "--stdin")
  12054   :standard-input t
  12055   :error-patterns
  12056   ((error line-start
  12057           (or "Syntax error: " "Error: ")
  12058           (message (one-or-more not-newline)
  12059                    (zero-or-more "\n"
  12060                                  (one-or-more " ")
  12061                                  (one-or-more not-newline)))
  12062           (optional "\r") "\n" (one-or-more " ") "on line " line
  12063           " of standard input"
  12064           line-end)
  12065    (warning line-start
  12066             "WARNING: "
  12067             (message (one-or-more not-newline)
  12068                      (zero-or-more "\n"
  12069                                    (one-or-more " ")
  12070                                    (one-or-more not-newline)))
  12071             (optional "\r") "\n" (one-or-more " ") "on line " line
  12072             " of " (one-or-more not-newline)
  12073             line-end))
  12074   :modes sass-mode)
  12075 
  12076 (flycheck-def-config-file-var flycheck-sass-lintrc sass/scss-sass-lint
  12077                               ".sass-lint.yml"
  12078   :package-version '(flycheck . "30"))
  12079 
  12080 (flycheck-define-checker sass/scss-sass-lint
  12081   "A SASS/SCSS syntax checker using sass-Lint.
  12082 
  12083 See URL `https://github.com/sasstools/sass-lint'."
  12084   :command ("sass-lint"
  12085             "--verbose"
  12086             "--no-exit"
  12087             "--format" "Checkstyle"
  12088             (config-file "--config" flycheck-sass-lintrc)
  12089             source)
  12090   :error-parser flycheck-parse-checkstyle
  12091   :modes (sass-mode scss-mode))
  12092 
  12093 (flycheck-define-checker scala
  12094   "A Scala syntax checker using the Scala compiler.
  12095 
  12096 See URL `https://www.scala-lang.org/'."
  12097   :command ("scalac" "-Ystop-after:parser" source)
  12098   :error-patterns
  12099   ((error line-start (file-name) ":" line ": error: " (message) line-end))
  12100   :modes scala-mode
  12101   :next-checkers ((warning . scala-scalastyle)))
  12102 
  12103 (flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil
  12104   :package-version '(flycheck . "0.20"))
  12105 
  12106 (flycheck-define-checker scala-scalastyle
  12107   "A Scala style checker using scalastyle.
  12108 
  12109 Note that this syntax checker is not used if
  12110 `flycheck-scalastylerc' is nil or refers to a non-existing file.
  12111 
  12112 See URL `https://www.scalastyle.org'."
  12113   :command ("scalastyle"
  12114             (config-file "-c" flycheck-scalastylerc)
  12115             source)
  12116   :error-patterns
  12117   ((error line-start "error file=" (file-name) " message="
  12118           (message) " line=" line (optional " column=" column) line-end)
  12119    (warning line-start "warning file=" (file-name) " message="
  12120             (message) " line=" line (optional " column=" column) line-end))
  12121   :error-filter (lambda (errors)
  12122                   (flycheck-sanitize-errors
  12123                    (flycheck-increment-error-columns errors)))
  12124   :modes scala-mode
  12125   :predicate
  12126   ;; Inhibit this syntax checker if the JAR or the configuration are unset or
  12127   ;; missing
  12128   (lambda () (and flycheck-scalastylerc
  12129                   (flycheck-locate-config-file flycheck-scalastylerc
  12130                                                'scala-scalastyle)))
  12131   :verify (lambda (checker)
  12132             (let ((config-file (and flycheck-scalastylerc
  12133                                     (flycheck-locate-config-file
  12134                                      flycheck-scalastylerc checker))))
  12135               (list
  12136                (flycheck-verification-result-new
  12137                 :label "Configuration file"
  12138                 :message (cond
  12139                           ((not flycheck-scalastylerc)
  12140                            "`flycheck-scalastyletrc' not set")
  12141                           ((not config-file)
  12142                            (format "file %s not found" flycheck-scalastylerc))
  12143                           (t (format "found at %s" config-file)))
  12144                 :face (cond
  12145                        ((not flycheck-scalastylerc) '(bold warning))
  12146                        ((not config-file) '(bold error))
  12147                        (t 'success)))))))
  12148 
  12149 (flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken
  12150   :package-version '(flycheck . "32"))
  12151 
  12152 (flycheck-define-checker scheme-chicken
  12153   "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'.
  12154 
  12155 See URL `https://call-cc.org/'."
  12156   :command ("csc" "-analyze-only" "-local"
  12157             (eval flycheck-scheme-chicken-args)
  12158             source)
  12159   :error-patterns
  12160   ((info line-start
  12161          "Note: " (zero-or-more not-newline) ":\n"
  12162          (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12163          line-end)
  12164    (warning line-start
  12165             "Warning: " (zero-or-more not-newline) ",\n"
  12166             (one-or-more (any space)) (zero-or-more not-newline) ":\n"
  12167             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12168             line-end)
  12169    (warning line-start
  12170             "Warning: " (zero-or-more not-newline) ":\n"
  12171             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12172             line-end)
  12173    (error line-start "Error: (line " line ") " (message) line-end)
  12174    (error line-start "Syntax error: (" (file-name) ":" line ")"
  12175           (zero-or-more not-newline) " - "
  12176           (message (one-or-more not-newline)
  12177                    (zero-or-more "\n"
  12178                                  (zero-or-more space)
  12179                                  (zero-or-more not-newline))
  12180                    (one-or-more space) "<--")
  12181           line-end)
  12182    ;; A of version 4.12.0, the chicken compiler doesn't provide a
  12183    ;; line number for this error.
  12184    (error line-start "Syntax error: "
  12185           (message (one-or-more not-newline)
  12186                    (zero-or-more "\n"
  12187                                  (zero-or-more space)
  12188                                  (zero-or-more not-newline))
  12189                    (one-or-more space) "<--")
  12190           line-end)
  12191    (error line-start
  12192           "Error: " (zero-or-more not-newline) ":\n"
  12193           (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12194           line-end)
  12195    ;; A of version 4.12.0, the chicken compiler doesn't provide a
  12196    ;; line number for this error.
  12197    (error line-start "Error: "
  12198           (message (one-or-more not-newline)
  12199                    (zero-or-more "\n"
  12200                                  (zero-or-more space)
  12201                                  (zero-or-more not-newline))
  12202                    (one-or-more space) "<--")))
  12203   :error-filter flycheck-fill-empty-line-numbers
  12204   :predicate
  12205   (lambda ()
  12206     ;; In `scheme-mode' we must check the current Scheme implementation
  12207     ;; being used
  12208     (and (boundp 'geiser-impl--implementation)
  12209          (eq geiser-impl--implementation 'chicken)))
  12210   :verify
  12211   (lambda (_checker)
  12212     (let ((geiser-impl (bound-and-true-p geiser-impl--implementation)))
  12213       (list
  12214        (flycheck-verification-result-new
  12215         :label "Geiser Implementation"
  12216         :message (cond
  12217                   ((eq geiser-impl 'chicken) "Chicken Scheme")
  12218                   (geiser-impl (format "Other: %s" geiser-impl))
  12219                   (t "Geiser not active"))
  12220         :face (cond
  12221                ((eq geiser-impl 'chicken) 'success)
  12222                (t '(bold error)))))))
  12223   :modes scheme-mode)
  12224 
  12225 (defconst flycheck-scss-lint-checkstyle-re
  12226   (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle")
  12227   "Regular expression to parse missing checkstyle error.")
  12228 
  12229 (defun flycheck-parse-scss-lint (output checker buffer)
  12230   "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER.
  12231 
  12232 Like `flycheck-parse-checkstyle', but catches errors about
  12233 missing checkstyle reporter from SCSS-Lint."
  12234   (if (string-match-p flycheck-scss-lint-checkstyle-re output)
  12235       (list (flycheck-error-new-at
  12236              1 nil 'error "Checkstyle reporter for SCSS-Lint missing.
  12237 Please run gem install scss_lint_reporter_checkstyle"
  12238              :checker checker
  12239              :buffer buffer
  12240              :filename (buffer-file-name buffer)))
  12241     (flycheck-parse-checkstyle output checker buffer)))
  12242 
  12243 (flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml"
  12244   :package-version '(flycheck . "0.23"))
  12245 
  12246 (flycheck-define-checker scss-lint
  12247   "A SCSS syntax checker using SCSS-Lint.
  12248 
  12249 Needs SCSS-Lint 0.43.2 or newer.
  12250 
  12251 See URL `https://github.com/brigade/scss-lint'."
  12252   :command ("scss-lint"
  12253             "--require=scss_lint_reporter_checkstyle"
  12254             "--format=Checkstyle"
  12255             (config-file "--config" flycheck-scss-lintrc)
  12256             "--stdin-file-path" source-original "-")
  12257   :standard-input t
  12258   ;; We cannot directly parse Checkstyle XML, since for some mysterious reason
  12259   ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it
  12260   ;; as an addon which might not be installed.  We use a custom error parser to
  12261   ;; check whether the addon is missing and turn that into a special kind of
  12262   ;; Flycheck error.
  12263   :error-parser flycheck-parse-scss-lint
  12264   :modes scss-mode
  12265   :verify
  12266   (lambda (checker)
  12267     (when-let
  12268         (output (flycheck-call-checker-process-for-output
  12269                  checker nil nil "--require=scss_lint_reporter_checkstyle"))
  12270       (let ((reporter-missing
  12271              (string-match-p flycheck-scss-lint-checkstyle-re output)))
  12272         (list
  12273          (flycheck-verification-result-new
  12274           :label "checkstyle reporter"
  12275           :message (if reporter-missing
  12276                        "scss_lint_reporter_checkstyle plugin missing"
  12277                      "present")
  12278           :face (if reporter-missing
  12279                     '(bold error)
  12280                   'success)))))))
  12281 
  12282 (flycheck-define-checker scss-stylelint
  12283   "A SCSS syntax and style checker using stylelint.
  12284 
  12285 See URL `https://stylelint.io/'."
  12286   :command ("stylelint"
  12287             (eval flycheck-stylelint-args)
  12288             (option-flag "--quiet" flycheck-stylelint-quiet)
  12289             (config-file "--config" flycheck-stylelintrc))
  12290   :standard-input t
  12291   :verify (lambda (_) (flycheck--stylelint-verify 'scss-stylelint))
  12292   :error-parser flycheck-parse-stylelint
  12293   :predicate flycheck-buffer-nonempty-p
  12294   :modes (scss-mode))
  12295 
  12296 (flycheck-define-checker sass-stylelint
  12297   "A Sass syntax and style checker using stylelint.
  12298 
  12299 See URL `https://stylelint.io/'."
  12300   :command ("stylelint"
  12301             (eval flycheck-stylelint-args)
  12302             (option-flag "--quiet" flycheck-stylelint-quiet)
  12303             (config-file "--config" flycheck-stylelintrc))
  12304   :standard-input t
  12305   :verify (lambda (_) (flycheck--stylelint-verify 'sass-stylelint))
  12306   :error-parser flycheck-parse-stylelint
  12307   :predicate flycheck-buffer-nonempty-p
  12308   :modes (sass-mode))
  12309 
  12310 (flycheck-def-option-var flycheck-scss-compass nil scss
  12311   "Whether to enable the Compass CSS framework.
  12312 
  12313 When non-nil, enable the Compass CSS framework, via `--compass'."
  12314   :type 'boolean
  12315   :safe #'booleanp
  12316   :package-version '(flycheck . "0.16"))
  12317 
  12318 (flycheck-define-checker scss
  12319   "A SCSS syntax checker using the SCSS compiler.
  12320 
  12321 See URL `https://sass-lang.com'."
  12322   :command ("scss"
  12323             "--cache-location" (eval (flycheck-sass-scss-cache-location))
  12324             (option-flag "--compass" flycheck-scss-compass)
  12325             "--check" "--stdin")
  12326   :standard-input t
  12327   :error-patterns
  12328   ((error line-start
  12329           (or "Syntax error: " "Error: ")
  12330           (message (one-or-more not-newline)
  12331                    (zero-or-more "\n"
  12332                                  (one-or-more " ")
  12333                                  (one-or-more not-newline)))
  12334           (optional "\r") "\n" (one-or-more " ") "on line " line
  12335           " of standard input"
  12336           line-end)
  12337    (warning line-start
  12338             "WARNING: "
  12339             (message (one-or-more not-newline)
  12340                      (zero-or-more "\n"
  12341                                    (one-or-more " ")
  12342                                    (one-or-more not-newline)))
  12343             (optional "\r") "\n" (one-or-more " ") "on line " line
  12344             " of an unknown file"
  12345             line-end))
  12346   :modes scss-mode)
  12347 
  12348 (flycheck-def-args-var flycheck-sh-bash-args (sh-bash)
  12349   :package-version '(flycheck . "32"))
  12350 
  12351 (flycheck-define-checker sh-bash
  12352   "A Bash syntax checker using the Bash shell.
  12353 
  12354 See URL `https://www.gnu.org/software/bash/'."
  12355   :command ("bash" "--norc" "-n"
  12356             (eval flycheck-sh-bash-args)
  12357             "--")
  12358   :standard-input t
  12359   :error-patterns
  12360   ((error line-start
  12361           ;; The name/path of the bash executable
  12362           (one-or-more (not (any ":"))) ":"
  12363           ;; A label "line", possibly localized
  12364           (one-or-more (not (any digit)))
  12365           line (zero-or-more " ") ":" (zero-or-more " ")
  12366           (message) line-end))
  12367   :modes (sh-mode bash-ts-mode)
  12368   :predicate (lambda () (eq sh-shell 'bash))
  12369   :next-checkers ((warning . sh-shellcheck)))
  12370 
  12371 (flycheck-define-checker sh-posix-dash
  12372   "A POSIX Shell syntax checker using the Dash shell.
  12373 
  12374 See URL `https://gondor.apana.org.au/~herbert/dash/'."
  12375   :command ("dash" "-n")
  12376   :standard-input t
  12377   :error-patterns
  12378   ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message)))
  12379   :modes sh-mode
  12380   :predicate (lambda () (eq sh-shell 'sh))
  12381   :next-checkers ((warning . sh-shellcheck)))
  12382 
  12383 (flycheck-define-checker sh-posix-bash
  12384   "A POSIX Shell syntax checker using the Bash shell.
  12385 
  12386 See URL `https://www.gnu.org/software/bash/'."
  12387   :command ("bash" "--posix" "--norc" "-n" "--")
  12388   :standard-input t
  12389   :error-patterns
  12390   ((error line-start
  12391           ;; The name/path of the bash executable
  12392           (one-or-more (not (any ":"))) ":"
  12393           ;; A label "line", possibly localized
  12394           (one-or-more (not (any digit)))
  12395           line (zero-or-more " ") ":" (zero-or-more " ")
  12396           (message) line-end))
  12397   :modes sh-mode
  12398   :predicate (lambda () (eq sh-shell 'sh))
  12399   :next-checkers ((warning . sh-shellcheck)))
  12400 
  12401 (flycheck-define-checker sh-zsh
  12402   "A Zsh syntax checker using the Zsh shell.
  12403 
  12404 See URL `https://www.zsh.org/'."
  12405   :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source)
  12406   :error-patterns
  12407   ((error line-start (file-name) ":" line ": " (message) line-end))
  12408   :modes sh-mode
  12409   :predicate (lambda () (eq sh-shell 'zsh))
  12410   :next-checkers ((warning . sh-shellcheck)))
  12411 
  12412 (defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh)
  12413   "Shells supported by ShellCheck.")
  12414 
  12415 (flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck
  12416   "A list of excluded warnings for ShellCheck.
  12417 
  12418 The value of this variable is a list of strings, where each
  12419 string is a warning code to be excluded from ShellCheck reports.
  12420 By default, no warnings are excluded."
  12421   :type '(repeat :tag "Excluded warnings"
  12422                  (string :tag "Warning code"))
  12423   :safe #'flycheck-string-list-p
  12424   :package-version '(flycheck . "0.21"))
  12425 
  12426 (flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck
  12427   "Whether to follow external sourced files in scripts.
  12428 
  12429 Shellcheck will follow and parse sourced files so long as a
  12430 pre-runtime resolvable path to the file is present.  This can
  12431 either be part of the source command itself:
  12432    source /full/path/to/file.txt
  12433 or added as a shellcheck directive before the source command:
  12434    # shellcheck source=/full/path/to/file.txt."
  12435   :type 'boolean
  12436   :safe #'booleanp
  12437   :package-version '(flycheck . "31"))
  12438 
  12439 (flycheck-define-checker sh-shellcheck
  12440   "A shell script syntax and style checker using Shellcheck.
  12441 
  12442 See URL `https://github.com/koalaman/shellcheck/'."
  12443   :command ("shellcheck"
  12444             "--format" "checkstyle"
  12445             "--shell" (eval (symbol-name sh-shell))
  12446             (option-flag "--external-sources"
  12447                          flycheck-shellcheck-follow-sources)
  12448             (option "--exclude" flycheck-shellcheck-excluded-warnings list
  12449                     flycheck-option-comma-separated-list)
  12450             "-")
  12451   :standard-input t
  12452   :error-parser flycheck-parse-checkstyle
  12453   :error-filter
  12454   (lambda (errors)
  12455     (flycheck-remove-error-file-names
  12456      "-" (flycheck-dequalify-error-ids errors)))
  12457   :modes (sh-mode bash-ts-mode)
  12458   :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells))
  12459   :verify (lambda (_)
  12460             (let ((supports-shell (memq sh-shell
  12461                                         flycheck-shellcheck-supported-shells)))
  12462               (list
  12463                (flycheck-verification-result-new
  12464                 :label (format "Shell %s supported" sh-shell)
  12465                 :message (if supports-shell "yes" "no")
  12466                 :face (if supports-shell 'success '(bold warning))))))
  12467   :error-explainer
  12468   (lambda (err)
  12469     (let ((error-code (flycheck-error-id err))
  12470           (url "https://github.com/koalaman/shellcheck/wiki/%s"))
  12471       (and error-code `(url . ,(format url error-code))))))
  12472 
  12473 (flycheck-define-checker slim
  12474   "A Slim syntax checker using the Slim compiler.
  12475 
  12476 See URL `https://slim-lang.com'."
  12477   :command ("slimrb" "--compile")
  12478   :standard-input t
  12479   :error-patterns
  12480   ((error line-start
  12481           "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n  "
  12482           "STDIN, Line " line (optional ", Column " column)
  12483           line-end))
  12484   :modes slim-mode
  12485   :next-checkers ((warning . slim-lint)))
  12486 
  12487 (flycheck-define-checker slim-lint
  12488   "A Slim linter.
  12489 
  12490 See URL `https://github.com/sds/slim-lint'."
  12491   :command ("slim-lint" "--reporter=checkstyle" source)
  12492   :error-parser flycheck-parse-checkstyle
  12493   :modes slim-mode)
  12494 
  12495 (flycheck-define-checker sql-sqlint
  12496   "A SQL syntax checker using the sqlint tool.
  12497 
  12498 See URL `https://github.com/purcell/sqlint'."
  12499   :command ("sqlint")
  12500   :standard-input t
  12501   :error-patterns
  12502   ((warning line-start "stdin:" line ":" column ":WARNING "
  12503             (message (one-or-more not-newline)
  12504                      (zero-or-more "\n"
  12505                                    (one-or-more "  ")
  12506                                    (one-or-more not-newline)))
  12507             line-end)
  12508    (error line-start "stdin:" line ":" column ":ERROR "
  12509           (message (one-or-more not-newline)
  12510                    (zero-or-more "\n"
  12511                                  (one-or-more "  ")
  12512                                  (one-or-more not-newline)))
  12513           line-end))
  12514   :modes (sql-mode))
  12515 
  12516 (flycheck-define-checker systemd-analyze
  12517   "A systemd unit checker using systemd-analyze(1).
  12518 
  12519 See URL
  12520 `https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'."
  12521   :command ("systemd-analyze" "verify" source)
  12522   :error-parser flycheck-parse-with-patterns-without-color
  12523   :error-patterns
  12524   ((error line-start (file-name) ":" (optional line ":") (message) line-end)
  12525    (error line-start "[" (file-name) ":" line "]" (message) line-end))
  12526   :error-filter (lambda (errors)
  12527                   (flycheck-sanitize-errors
  12528                    (flycheck-fill-empty-line-numbers errors)))
  12529   :modes (systemd-mode))
  12530 
  12531 (flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc")
  12532 
  12533 (flycheck-define-checker tcl-nagelfar
  12534   "An extensible tcl syntax checker
  12535 
  12536 See URL `https://nagelfar.sourceforge.net/'."
  12537   :command ("nagelfar" "-H" source)
  12538   :error-patterns
  12539   ;; foo.tcl: 29: E Wrong number of arguments (4) to "set"
  12540   ;; foo.tcl: 29: W Expr without braces
  12541   ((info    line-start (file-name) ": " line ": N " (message) line-end)
  12542    (warning line-start (file-name) ": " line ": W " (message) line-end)
  12543    (error   line-start (file-name) ": " line ": E " (message) line-end))
  12544   :modes tcl-mode)
  12545 
  12546 (flycheck-define-checker terraform
  12547   "A Terraform syntax checker with `terraform fmt'.
  12548 
  12549 See URL `https://www.terraform.io/docs/commands/fmt.html'."
  12550   :command ("terraform" "fmt" "-no-color" "-")
  12551   :standard-input t
  12552   :error-patterns
  12553   ((error line-start "Error: " (one-or-more not-newline)
  12554           "\n\n  on <stdin> line " line ", in " (one-or-more not-newline) ":"
  12555           (one-or-more "\n" (zero-or-more space (one-or-more not-newline)))
  12556           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
  12557           line-end)
  12558    (error line-start "Error: " (one-or-more not-newline)
  12559           "\n\n  on <stdin> line " line ":\n  (source code not available)\n\n"
  12560           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
  12561           line-end))
  12562   :next-checkers ((warning . terraform-tflint))
  12563   :modes terraform-mode)
  12564 
  12565 (flycheck-def-option-var flycheck-tflint-variable-files nil terraform-tflint
  12566   "A list of files to resolve terraform variables.
  12567 
  12568 The value of this variable is a list of strings, where each
  12569 string is a file to add to the terraform variables files.
  12570 Relative files are relative to the file being checked."
  12571   :type '(repeat (directory :tag "Variable file"))
  12572   :safe #'flycheck-string-list-p
  12573   :package-version '(flycheck . "32"))
  12574 
  12575 (defun flycheck-parse-tflint-linter (output checker buffer)
  12576   "Parse tflint warnings from JSON OUTPUT.
  12577 
  12578 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  12579 the BUFFER that was checked respectively.
  12580 
  12581 See URL `https://github.com/terraform-linters/tflint' for more
  12582 information about tflint."
  12583   (mapcar (lambda (err)
  12584             (let-alist err
  12585               (flycheck-error-new-at
  12586                .range.start.line
  12587                .range.start.column
  12588                (pcase .rule.severity
  12589                  ("error"   'error)
  12590                  ("warning" 'warning)
  12591                  (_         'error))
  12592                .message
  12593                :end-line .range.end.line
  12594                :end-column .range.end.column
  12595                :id .rule.name
  12596                :checker checker
  12597                :buffer buffer
  12598                :filename (buffer-file-name buffer))))
  12599           (cdr (assq 'issues (car (flycheck-parse-json output))))))
  12600 
  12601 (flycheck-define-checker terraform-tflint
  12602   "A Terraform checker using tflint.
  12603 
  12604 See URL `https://github.com/terraform-linters/tflint'."
  12605   :command ("tflint" "--format=json" "--force"
  12606             (option-list "--var-file=" flycheck-tflint-variable-files concat))
  12607   :error-parser flycheck-parse-tflint-linter
  12608   :predicate flycheck-buffer-saved-p
  12609   :modes terraform-mode)
  12610 
  12611 (flycheck-def-option-var flycheck-chktex-extra-flags nil tex-chktex
  12612   "A list of extra arguments to give to chktex.
  12613 This variable works the same way as `tex-chktex-extra-flags': its value
  12614 is a list of strings, where each string is an argument added to chktex.
  12615 
  12616 For example, to ignore warnings 8 and 18, you would set this option to
  12617 
  12618   \\='(\"-n8\" \"-n18\")."
  12619   :type '(repeat string)
  12620   :safe #'flycheck-string-list-p
  12621   :package-version '(flycheck . "35"))
  12622 
  12623 (flycheck-define-checker tex-chktex
  12624   "A TeX and LaTeX syntax and style checker using chktex.
  12625 
  12626 See URL `https://www.nongnu.org/chktex/'."
  12627   :command ("chktex"
  12628             (config-file "--localrc" flycheck-chktexrc)
  12629             (option-list "" flycheck-chktex-extra-flags concat)
  12630             ;; Compact error messages, and no version information, and execute
  12631             ;; \input statements
  12632             "--verbosity=0" "--quiet" "--inputfiles")
  12633   :standard-input t
  12634   :error-patterns
  12635   ((warning line-start "stdin:" line ":" column ":"
  12636             (id (one-or-more digit)) ":" (message) line-end))
  12637   :error-filter
  12638   (lambda (errors)
  12639     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
  12640   :modes (latex-mode LaTeX-mode plain-tex-mode plain-TeX-mode))
  12641 
  12642 (flycheck-define-checker tex-lacheck
  12643   "A LaTeX syntax and style checker using lacheck.
  12644 
  12645 See URL `https://www.ctan.org/pkg/lacheck'."
  12646   :command ("lacheck" source-inplace)
  12647   :error-patterns
  12648   ((warning line-start
  12649             "\"" (file-name) "\", line " line ": " (message)
  12650             line-end))
  12651   :modes (latex-mode LaTeX-mode))
  12652 
  12653 (flycheck-define-checker texinfo
  12654   "A Texinfo syntax checker using makeinfo.
  12655 
  12656 See URL `https://www.gnu.org/software/texinfo/'."
  12657   :command ("makeinfo" "-o" null-device "-")
  12658   :standard-input t
  12659   :error-patterns
  12660   ((warning line-start
  12661             "-:" line (optional ":" column) ": " "warning: " (message)
  12662             line-end)
  12663    (error line-start
  12664           "-:" line (optional ":" column) ": " (message)
  12665           line-end))
  12666   :modes (texinfo-mode Texinfo-mode))
  12667 
  12668 (flycheck-def-config-file-var flycheck-textlint-config
  12669     textlint "textlintrc.json")
  12670 
  12671 ;; This needs to be set because textlint plugins are installed separately,
  12672 ;; and there is no way to check their installation status -- textlint simply
  12673 ;; prints a backtrace.
  12674 (flycheck-def-option-var flycheck-textlint-plugin-alist
  12675     '((markdown-mode . "@textlint/markdown")
  12676       (gfm-mode . "@textlint/markdown")
  12677       (t . "@textlint/text"))
  12678     textlint
  12679   "An alist mapping major modes to textlint plugins.
  12680 
  12681 Each item is a cons cell `(MAJOR-MODE . PLUGIN)', where MAJOR-MODE is a mode
  12682 `flycheck-textlint' supports and PLUGIN is a textlint plugin. As a catch-all,
  12683 when MAJOR-MODE is t, that PLUGIN will be used for any supported mode that
  12684 isn't specified.
  12685 
  12686 See URL `https://npms.io/search?q=textlint-plugin' for all textlint plugins
  12687 published on NPM."
  12688   :type '(repeat (choice (cons symbol string)
  12689                          (cons (const t) string))))
  12690 
  12691 (defun flycheck--textlint-get-plugin ()
  12692   "Return the textlint plugin for the current mode."
  12693   (cdr (seq-find
  12694         (lambda (arg)
  12695           (pcase-let ((`(,mode . _) arg))
  12696             (or (and (booleanp mode) mode) ; mode is t
  12697                 (derived-mode-p mode))))
  12698         flycheck-textlint-plugin-alist)))
  12699 
  12700 (flycheck-define-checker textlint
  12701   "A text prose linter using textlint.
  12702 
  12703 See URL `https://textlint.github.io/'."
  12704   :command ("textlint"
  12705             (config-file "--config" flycheck-textlint-config)
  12706             "--format" "json"
  12707             ;; get the first matching plugin from plugin-alist
  12708             "--plugin"
  12709             (eval (flycheck--textlint-get-plugin))
  12710             source)
  12711   ;; textlint seems to say that its json output is compatible with ESLint.
  12712   ;; https://textlint.github.io/docs/formatter.html
  12713   :error-parser flycheck-parse-eslint
  12714   ;; textlint can support different formats with textlint plugins, but
  12715   ;; only text and markdown formats are installed by default. Ask the
  12716   ;; user to add mode->plugin mappings manually in
  12717   ;; `flycheck-textlint-plugin-alist'.
  12718   :modes
  12719   (text-mode markdown-mode gfm-mode message-mode adoc-mode
  12720              mhtml-mode latex-mode LaTeX-mode org-mode rst-mode)
  12721   :enabled
  12722   (lambda () (flycheck--textlint-get-plugin))
  12723   :verify
  12724   (lambda (_)
  12725     (let ((plugin (flycheck--textlint-get-plugin)))
  12726       (list
  12727        (flycheck-verification-result-new
  12728         :label "textlint plugin"
  12729         :message plugin
  12730         :face 'success)))))
  12731 
  12732 (flycheck-def-config-file-var flycheck-typescript-tslint-config
  12733     typescript-tslint "tslint.json"
  12734   :package-version '(flycheck . "27"))
  12735 
  12736 (flycheck-def-option-var flycheck-typescript-tslint-rulesdir
  12737     nil typescript-tslint
  12738   "The directory of custom rules for TSLint.
  12739 
  12740 The value of this variable is either a string containing the path
  12741 to a directory with custom rules, or nil, to not give any custom
  12742 rules to TSLint.
  12743 
  12744 Refer to the TSLint manual at URL
  12745 `https://palantir.github.io/tslint/usage/cli/'
  12746 for more information about the custom directory."
  12747   :type '(choice (const :tag "No custom rules directory" nil)
  12748                  (directory :tag "Custom rules directory"))
  12749   :safe #'flycheck-string-or-nil-p
  12750   :package-version '(flycheck . "27"))
  12751 
  12752 (flycheck-def-args-var flycheck-tslint-args (typescript-tslint)
  12753   :package-version '(flycheck . "31"))
  12754 
  12755 (flycheck-define-checker typescript-tslint
  12756   "TypeScript style checker using TSLint.
  12757 
  12758 Note that this syntax checker is not used if
  12759 `flycheck-typescript-tslint-config' is nil or refers to a
  12760 non-existing file.
  12761 
  12762 See URL `https://github.com/palantir/tslint'."
  12763   :command ("tslint" "--format" "json"
  12764             (config-file "--config" flycheck-typescript-tslint-config)
  12765             (option "--rules-dir" flycheck-typescript-tslint-rulesdir)
  12766             (eval flycheck-tslint-args)
  12767             source-inplace)
  12768   :error-parser flycheck-parse-tslint
  12769   :modes (typescript-mode typescript-ts-mode tsx-ts-mode))
  12770 
  12771 (flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator
  12772   "A list of include directories for Verilator.
  12773 
  12774 The value of this variable is a list of strings, where each
  12775 string is a directory to add to the include path of Verilator.
  12776 Relative paths are relative to the file being checked."
  12777   :type '(repeat (directory :tag "Include directory"))
  12778   :safe #'flycheck-string-list-p
  12779   :package-version '(flycheck . "0.24"))
  12780 
  12781 (flycheck-define-checker verilog-verilator
  12782   "A Verilog syntax checker using the Verilator Verilog HDL simulator.
  12783 
  12784 See URL `https://www.veripool.org/wiki/verilator'."
  12785   :command ("verilator" "--lint-only" "-Wall" "--quiet-exit"
  12786             (option-list "-I" flycheck-verilator-include-path concat)
  12787             source)
  12788   :error-patterns
  12789   ((warning line-start "%Warning"
  12790             (? "-" (id (+ (any "0-9A-Z_")))) ": "
  12791             (? (file-name) ":" line ":" (? column ":") " ")
  12792             (message) line-end)
  12793    (error line-start "%Error"
  12794           (? "-" (id (+ (any "0-9A-Z_")))) ": "
  12795           (? (file-name) ":" line ":" (? column ":") " ")
  12796           (message) line-end))
  12797   :modes verilog-mode)
  12798 
  12799 (flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl
  12800   "The language standard to use in GHDL.
  12801 
  12802 The value of this variable is either a string denoting a language
  12803 standard, or nil, to use the default standard.  When non-nil,
  12804 pass the language standard via the `--std' option."
  12805   :type '(choice (const :tag "Default standard" nil)
  12806                  (string :tag "Language standard"))
  12807   :safe #'flycheck-string-or-nil-p
  12808   :package-version '(flycheck . "32"))
  12809 (make-variable-buffer-local 'flycheck-ghdl-language-standard)
  12810 
  12811 (flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl
  12812   "The directory to use for the file library.
  12813 
  12814 The value of this variable is either a string with the directory
  12815 to use for the file library, or nil, to use the default value.
  12816 When non-nil, pass the directory via the `--workdir' option."
  12817   :type '(choice (const :tag "Default directory" nil)
  12818                  (string :tag "Directory for the file library"))
  12819   :safe #'flycheck-string-or-nil-p
  12820   :package-version '(flycheck . "32"))
  12821 (make-variable-buffer-local 'flycheck-ghdl-workdir)
  12822 
  12823 (flycheck-def-option-var flycheck-ghdl-ieee-library nil vhdl-ghdl
  12824   "The standard to use for the IEEE library.
  12825 
  12826 The value of this variable is either a string denoting an ieee library
  12827 standard, or nil, to use the default standard.  When non-nil,
  12828 pass the ieee library standard via the `--ieee' option."
  12829   :type '(choice (const :tag "Default standard" nil)
  12830                  (const :tag "No IEEE Library" "none")
  12831                  (const :tag "IEEE standard" "standard")
  12832                  (const :tag "Synopsys standard" "synopsys")
  12833                  (const :tag "Mentor standard" "mentor"))
  12834   :safe #'flycheck-string-or-nil-p
  12835   :package-version '(flycheck . "32"))
  12836 (make-variable-buffer-local 'flycheck-ghdl-ieee-library)
  12837 
  12838 (flycheck-define-checker vhdl-ghdl
  12839   "A VHDL syntax checker using GHDL.
  12840 
  12841 See URL `https://github.com/ghdl/ghdl'."
  12842   :command ("ghdl"
  12843             "-s" ; only do the syntax checking
  12844             (option "--std=" flycheck-ghdl-language-standard concat)
  12845             (option "--workdir=" flycheck-ghdl-workdir concat)
  12846             (option "--ieee=" flycheck-ghdl-ieee-library concat)
  12847             source)
  12848   :error-patterns
  12849   ((warning line-start (file-name) ":" line ":" column ":warning: " (message) line-end)
  12850    (error line-start (file-name) ":" line ":" column ":error: " (message) line-end))
  12851   :modes vhdl-mode)
  12852 
  12853 (flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet
  12854   "An XSD schema to validate against."
  12855   :type '(choice (const :tag "None" nil)
  12856                  (file :tag "XSD schema"))
  12857   :safe #'flycheck-string-or-nil-p
  12858   :package-version '(flycheck . "31"))
  12859 
  12860 (flycheck-define-checker xml-xmlstarlet
  12861   "A XML syntax checker and validator using the xmlstarlet utility.
  12862 
  12863 See URL `https://xmlstar.sourceforge.net/'."
  12864   ;; Validate standard input with verbose error messages, and do not dump
  12865   ;; contents to standard output
  12866   :command ("xmlstarlet" "val" "--err" "--quiet"
  12867             (option "--xsd" flycheck-xml-xmlstarlet-xsd-path)
  12868             "-")
  12869   :standard-input t
  12870   :error-patterns
  12871   ((error line-start "-:" line "." column ": " (message) line-end))
  12872   :modes (xml-mode nxml-mode))
  12873 
  12874 (flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint
  12875   "An XSD schema to validate against."
  12876   :type '(choice (const :tag "None" nil)
  12877                  (file :tag "XSD schema"))
  12878   :safe #'flycheck-string-or-nil-p
  12879   :package-version '(flycheck . "31"))
  12880 
  12881 (flycheck-def-option-var flycheck-xml-xmllint-relaxng-path nil xml-xmllint
  12882   "An RELAX NG schema to validate against."
  12883   :type '(choice (const :tag "None" nil)
  12884                  (file :tag "RELAX NG schema"))
  12885   :safe #'flycheck-string-or-nil-p
  12886   :package-version '(flycheck . "34"))
  12887 
  12888 (flycheck-define-checker xml-xmllint
  12889   "A XML syntax checker and validator using the xmllint utility.
  12890 
  12891 The xmllint is part of libxml2, see URL
  12892 `https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home'."
  12893   :command ("xmllint" "--noout"
  12894             (option "--schema" flycheck-xml-xmllint-xsd-path)
  12895             (option "--relaxng" flycheck-xml-xmllint-relaxng-path)
  12896             "-")
  12897   :standard-input t
  12898   :error-patterns
  12899   ((error line-start "-:" line ": " (message) line-end))
  12900   :modes (xml-mode nxml-mode))
  12901 
  12902 (flycheck-define-checker yaml-jsyaml
  12903   "A YAML syntax checker using JS-YAML.
  12904 
  12905 See URL `https://github.com/nodeca/js-yaml'."
  12906   :command ("js-yaml")
  12907   :standard-input t
  12908   :error-patterns
  12909   ((error line-start
  12910           (or "JS-YAML" "YAMLException") ": "
  12911           (message) " at line " line ", column " column ":"
  12912           line-end)
  12913    (error line-start
  12914           (or "JS-YAML" "YAMLException") ": "
  12915           (message) " (" line ":" column ")"
  12916           line-end))
  12917   :modes (yaml-mode yaml-ts-mode)
  12918   :next-checkers ((warning . yaml-yamllint)
  12919                   (warning . cwl)))
  12920 
  12921 (flycheck-define-checker yaml-ruby
  12922   "A YAML syntax checker using Ruby's YAML parser.
  12923 
  12924 This syntax checker uses the YAML parser from Ruby's standard
  12925 library.
  12926 
  12927 See URL `https://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'."
  12928   :command ("ruby" "-ryaml" "-e" "begin;
  12929    YAML.load(STDIN); \
  12930  rescue Exception => e; \
  12931    STDERR.puts \"stdin:#{e}\"; \
  12932  end")
  12933   :standard-input t
  12934   :error-patterns
  12935   ((error line-start "stdin:" (zero-or-more not-newline) ":" (message)
  12936           "at line " line " column " column line-end))
  12937   :modes (yaml-mode yaml-ts-mode)
  12938   :next-checkers ((warning . yaml-yamllint)
  12939                   (warning . cwl)))
  12940 
  12941 (flycheck-def-config-file-var flycheck-yamllintrc
  12942     yaml-yamllint
  12943     '(".yamllint"
  12944       ".yamllint.yaml"
  12945       ".yamllint.yml"
  12946       "~/.config/yamllint/config"))
  12947 
  12948 (flycheck-define-checker yaml-yamllint
  12949   "A YAML syntax checker using YAMLLint.
  12950 See URL `https://github.com/adrienverge/yamllint'."
  12951   :standard-input t
  12952   :command ("yamllint" "-f" "parsable" "-"
  12953             (config-file "-c" flycheck-yamllintrc))
  12954   :error-patterns
  12955   ((error line-start
  12956           "stdin:" line ":" column ": [error] " (message) line-end)
  12957    (warning line-start
  12958             "stdin:" line ":" column ": [warning] " (message) line-end))
  12959   :modes (yaml-mode yaml-ts-mode)
  12960   :next-checkers ((warning . cwl)))
  12961 
  12962 (provide 'flycheck)
  12963 
  12964 ;; Local Variables:
  12965 ;; coding: utf-8
  12966 ;; indent-tabs-mode: nil
  12967 ;; End:
  12968 
  12969 ;;; flycheck.el ends here