config

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

flycheck.el (513863B)


      1 ;;; flycheck.el --- On-the-fly syntax checking -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2017-2024 Flycheck contributors
      4 ;; Copyright (C) 2012-2016 Sebastian Wiesner and Flycheck contributors
      5 ;; Copyright (C) 2013, 2014 Free Software Foundation, Inc.
      6 ;;
      7 ;; Author: Sebastian Wiesner <swiesner@lunaryorn.com>
      8 ;; Maintainer: Clément Pit-Claudel <clement.pitclaudel@live.com>
      9 ;;             fmdkdd <fmdkdd@gmail.com>
     10 ;;             Bozhidar Batsov <bozhidar@batsov.dev>
     11 ;; URL: https://www.flycheck.org
     12 ;; Keywords: convenience, languages, tools
     13 ;; Version: 35.0-snapshot
     14 ;; Package-Requires: ((emacs "26.1"))
     15 
     16 ;; This file is not part of GNU Emacs.
     17 
     18 ;; This program is free software: you can redistribute it and/or modify
     19 ;; it under the terms of the GNU General Public License as published by
     20 ;; the Free Software Foundation, either version 3 of the License, or
     21 ;; (at your option) any later version.
     22 
     23 ;; This program is distributed in the hope that it will be useful,
     24 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     26 ;; GNU General Public License for more details.
     27 
     28 ;; You should have received a copy of the GNU General Public License
     29 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     30 
     31 ;;; Commentary:
     32 
     33 ;; On-the-fly syntax checking for GNU Emacs.
     34 ;;
     35 ;; Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs,
     36 ;; intended as replacement for the older Flymake extension which is part of GNU
     37 ;; Emacs.
     38 ;;
     39 ;; Flycheck automatically checks buffers for errors while you type, and reports
     40 ;; warnings and errors directly in the buffer and in an optional IDE-like error
     41 ;; list.
     42 ;;
     43 ;; It comes with a rich interface for custom syntax checkers and other
     44 ;; extensions, and has already many 3rd party extensions adding new features.
     45 ;;
     46 ;; Please read the online manual at https://www.flycheck.org for more
     47 ;; information.  You can open the manual directly from Emacs with `M-x
     48 ;; flycheck-manual'.
     49 ;;
     50 ;; # Setup
     51 ;;
     52 ;; Flycheck works best on Unix systems.  It does not officially support Windows,
     53 ;; but tries to maintain Windows compatibility and should generally work fine on
     54 ;; Windows, too.
     55 ;;
     56 ;; To enable Flycheck add the following to your init file:
     57 ;;
     58 ;;    (add-hook 'after-init-hook #'global-flycheck-mode)
     59 ;;
     60 ;; Flycheck will then automatically check buffers in supported languages, as
     61 ;; long as all necessary tools are present.  Use `flycheck-verify-setup' to
     62 ;; troubleshoot your Flycheck setup.
     63 
     64 ;;; Code:
     65 
     66 (eval-when-compile
     67   (require 'let-alist)      ; `let-alist'
     68   (require 'compile)        ; Compile Mode integration
     69   (require 'jka-compr)      ; To inhibit compression of temp files
     70   (require 'pcase)          ; `pcase-dolist' (`pcase' itself is autoloaded)
     71   )
     72 
     73 (require 'seq)                   ; Sequence functions
     74 (require 'subr-x)                ; Additional utilities
     75 (require 'cl-lib)                ; `cl-defstruct' and CL utilities
     76 (require 'tabulated-list)        ; To list errors
     77 (require 'easymenu)              ; Flycheck Mode menu definition
     78 (require 'rx)                    ; Regexp fanciness in `flycheck-define-checker'
     79 (require 'help-mode)             ; `define-button-type'
     80 (require 'find-func)             ; `find-function-regexp-alist'
     81 (require 'json)                  ; `flycheck-parse-json'
     82 (require 'ansi-color)            ; `flycheck-parse-with-patterns-without-color'
     83 
     84 
     85 ;; Declare a bunch of dynamic variables that we need from other modes
     86 (defvar sh-shell)                       ; For shell script checker predicates
     87 (defvar ess-language)                   ; For r-lintr predicate
     88 (defvar markdown-hide-markup)                     ;
     89 (defvar markdown-fontify-code-block-default-mode) ; For rust-error-explainer
     90 (defvar markdown-fontify-code-blocks-natively)    ;
     91 
     92 ;; Tell the byte compiler about autoloaded functions from packages
     93 (declare-function pkg-info-version-info "pkg-info" (package))
     94 
     95 
     96 ;;; Customization
     97 (defgroup flycheck nil
     98   "Modern on-the-fly syntax checking for GNU Emacs."
     99   :prefix "flycheck-"
    100   :group 'tools
    101   :link '(url-link :tag "Website" "https://www.flycheck.org")
    102   :link '(url-link :tag "Github" "https://github.com/flycheck/flycheck"))
    103 
    104 (defgroup flycheck-config-files nil
    105   "Configuration files for on-the-fly syntax checkers."
    106   :prefix "flycheck-"
    107   :group 'flycheck)
    108 
    109 (defgroup flycheck-options nil
    110   "Options for on-the-fly syntax checkers."
    111   :prefix "flycheck-"
    112   :group 'flycheck)
    113 
    114 (defgroup flycheck-executables nil
    115   "Executables of syntax checkers."
    116   :prefix "flycheck-"
    117   :group 'flycheck)
    118 
    119 (defgroup flycheck-faces nil
    120   "Faces used by on-the-fly syntax checking."
    121   :prefix "flycheck-"
    122   :group 'flycheck)
    123 
    124 (defcustom flycheck-checkers
    125   '(ada-gnat
    126     asciidoctor
    127     asciidoc
    128     awk-gawk
    129     bazel-build-buildifier
    130     bazel-module-buildifier
    131     bazel-starlark-buildifier
    132     bazel-workspace-buildifier
    133     c/c++-clang
    134     c/c++-gcc
    135     c/c++-cppcheck
    136     cfengine
    137     coffee
    138     coffee-coffeelint
    139     css-csslint
    140     css-stylelint
    141     cuda-nvcc
    142     cwl
    143     d-dmd
    144     dockerfile-hadolint
    145     elixir-credo
    146     emacs-lisp
    147     emacs-lisp-checkdoc
    148     ember-template
    149     erlang-rebar3
    150     erlang
    151     eruby-erubis
    152     eruby-ruumba
    153     fortran-gfortran
    154     go-gofmt
    155     go-vet
    156     go-build
    157     go-test
    158     go-errcheck
    159     go-unconvert
    160     go-staticcheck
    161     groovy
    162     haml
    163     haml-lint
    164     handlebars
    165     haskell-stack-ghc
    166     haskell-ghc
    167     haskell-hlint
    168     html-tidy
    169     javascript-eslint
    170     javascript-jshint
    171     javascript-standard
    172     json-jsonlint
    173     json-python-json
    174     json-jq
    175     jsonnet
    176     less
    177     less-stylelint
    178     llvm-llc
    179     lua-luacheck
    180     lua
    181     markdown-markdownlint-cli
    182     markdown-mdl
    183     markdown-pymarkdown
    184     nix
    185     nix-linter
    186     opam
    187     perl
    188     perl-perlcritic
    189     perl-perlimports
    190     php
    191     php-phpmd
    192     php-phpcs
    193     php-phpcs-changed
    194     processing
    195     proselint
    196     protobuf-protoc
    197     protobuf-prototool
    198     pug
    199     puppet-parser
    200     puppet-lint
    201     python-flake8
    202     python-ruff
    203     python-pylint
    204     python-pycompile
    205     python-pyright
    206     python-mypy
    207     r-lintr
    208     r
    209     racket
    210     rpm-rpmlint
    211     rst-sphinx
    212     rst
    213     ruby-rubocop
    214     ruby-chef-cookstyle
    215     ruby-standard
    216     ruby-reek
    217     ruby
    218     ruby-jruby
    219     rust-cargo
    220     rust
    221     rust-clippy
    222     salt-lint
    223     scala
    224     scala-scalastyle
    225     scheme-chicken
    226     scss-lint
    227     sass-stylelint
    228     scss-stylelint
    229     sass/scss-sass-lint
    230     sass
    231     scss
    232     sh-bash
    233     sh-posix-dash
    234     sh-posix-bash
    235     sh-zsh
    236     sh-shellcheck
    237     slim
    238     slim-lint
    239     sql-sqlint
    240     statix
    241     systemd-analyze
    242     tcl-nagelfar
    243     terraform
    244     terraform-tflint
    245     tex-chktex
    246     tex-lacheck
    247     texinfo
    248     textlint
    249     typescript-tslint
    250     verilog-verilator
    251     vhdl-ghdl
    252     xml-xmlstarlet
    253     xml-xmllint
    254     yaml-actionlint
    255     yaml-jsyaml
    256     yaml-ruby
    257     yaml-yamllint)
    258   "Syntax checkers available for automatic selection.
    259 
    260 A list of Flycheck syntax checkers to choose from when syntax
    261 checking a buffer.  Flycheck will automatically select a suitable
    262 syntax checker from this list, unless `flycheck-checker' is set,
    263 either directly or with `flycheck-select-checker'.
    264 
    265 You should not need to change this variable normally.  In order
    266 to disable syntax checkers, please use
    267 `flycheck-disabled-checkers'.  This variable is intended for 3rd
    268 party extensions to tell Flycheck about new syntax checkers.
    269 
    270 Syntax checkers in this list must be defined with
    271 `flycheck-define-checker'."
    272   :group 'flycheck
    273   :type '(repeat (symbol :tag "Checker"))
    274   :risky t)
    275 
    276 (defcustom flycheck-disabled-checkers nil
    277   "Syntax checkers excluded from automatic selection.
    278 
    279 A list of Flycheck syntax checkers to exclude from automatic
    280 selection.  Flycheck will never automatically select a syntax
    281 checker in this list, regardless of the value of
    282 `flycheck-checkers'.
    283 
    284 However, syntax checkers in this list are still available for
    285 manual selection with `flycheck-select-checker'.
    286 
    287 Use this variable to disable syntax checkers, instead of removing
    288 the syntax checkers from `flycheck-checkers'.  You may also use
    289 this option as a file or directory local variable to disable
    290 specific checkers in individual files and directories
    291 respectively."
    292   :group 'flycheck
    293   :type '(repeat (symbol :tag "Checker"))
    294   :package-version '(flycheck . "0.16")
    295   :safe #'flycheck-symbol-list-p)
    296 (make-variable-buffer-local 'flycheck-disabled-checkers)
    297 
    298 (defvar-local flycheck--automatically-disabled-checkers nil
    299   "List of syntax checkers automatically disabled for this buffer.
    300 
    301 A checker can be automatically disabled in two cases:
    302 
    303 1. Its `:enabled' predicate returned false.
    304 2. It returned too many errors (see `flycheck-checker-error-threshold').
    305 
    306 To trigger a reverification from Emacs Lisp code, do not modify
    307 this variable: use `flycheck-reset-enabled-checker'.")
    308 
    309 (defvar-local flycheck-checker nil
    310   "Syntax checker to use for the current buffer.
    311 
    312 If unset or nil, automatically select a suitable syntax checker
    313 from `flycheck-checkers' on every syntax check.
    314 
    315 If set to a syntax checker only use this syntax checker and never
    316 select one from `flycheck-checkers' automatically.  The syntax
    317 checker is used regardless of whether it is contained in
    318 `flycheck-checkers' or `flycheck-disabled-checkers'.  If the
    319 syntax checker is unusable in the current buffer an error is
    320 signaled.
    321 
    322 A syntax checker assigned to this variable must be defined with
    323 `flycheck-define-checker'.
    324 
    325 Use the command `flycheck-select-checker' to select a syntax
    326 checker for the current buffer, or set this variable as file
    327 local variable to always use a specific syntax checker for a
    328 file.  See Info Node `(Emacs)Specifying File Variables' for more
    329 information about file variables.")
    330 (put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p)
    331 
    332 (defcustom flycheck-locate-config-file-functions nil
    333   "Functions to locate syntax checker configuration files.
    334 
    335 Each function in this hook must accept two arguments: The value
    336 of the configuration file variable, and the syntax checker
    337 symbol.  It must return either a string with an absolute path to
    338 the configuration file, or nil, if it cannot locate the
    339 configuration file.
    340 
    341 The functions in this hook are called in order of appearance, until a
    342 function returns non-nil.  The configuration file returned by that
    343 function is then given to the syntax checker if it exists.
    344 
    345 This variable is an abnormal hook.  See Info
    346 node `(elisp)Hooks'."
    347   :group 'flycheck
    348   :type 'hook
    349   :risky t)
    350 
    351 (defcustom flycheck-checker-error-threshold 400
    352   "Maximum errors allowed per syntax checker.
    353 
    354 The value of this variable is either an integer denoting the
    355 maximum number of errors per syntax checker and buffer, or nil to
    356 not limit the errors reported from a syntax checker.
    357 
    358 If this variable is a number and a syntax checker reports more
    359 errors than the value of this variable, its errors are not
    360 discarded, and not highlighted in the buffer or available in the
    361 error list.  The affected syntax checker is also disabled for
    362 future syntax checks of the buffer."
    363   :group 'flycheck
    364   :type '(choice (const :tag "Do not limit reported errors" nil)
    365                  (integer :tag "Maximum number of errors"))
    366   :risky t
    367   :package-version '(flycheck . "0.22"))
    368 
    369 (defcustom flycheck-process-error-functions nil
    370   "Functions to process errors.
    371 
    372 Each function in this hook must accept a single argument: A
    373 Flycheck error to process.
    374 
    375 All functions in this hook are called in order of appearance,
    376 until a function returns non-nil.  Thus, a function in this hook
    377 may return nil, to allow for further processing of the error, or
    378 any non-nil value, to indicate that the error was fully processed
    379 and inhibit any further processing.
    380 
    381 The functions are called for each newly parsed error immediately
    382 after the corresponding syntax checker finished.  At this stage,
    383 the overlays from the previous syntax checks are still present,
    384 and there may be further syntax checkers in the chain.
    385 
    386 This variable is an abnormal hook.  See Info
    387 node `(elisp)Hooks'."
    388   :group 'flycheck
    389   :type 'hook
    390   :package-version '(flycheck . "0.13")
    391   :risky t)
    392 
    393 (defcustom flycheck-auto-display-errors-after-checking t
    394   "Whether to automatically display errors at the current point after checking.
    395 
    396 When being set to `nil', it will prevent Flycheck from automatically displaying
    397 error messages. This setting is useful when Flycheck is used together with
    398 `flycheck-posframe', to prevent `flycheck-posframe' from repeatedly displaying
    399 errors at point."
    400   :group 'flycheck
    401   :type 'boolean
    402   :package-version '(flycheck . "35")
    403   :safe #'booleanp)
    404 
    405 (defcustom flycheck-display-errors-delay 0.9
    406   "Delay in seconds before displaying errors at point.
    407 
    408 Use floating point numbers to express fractions of seconds."
    409   :group 'flycheck
    410   :type 'number
    411   :package-version '(flycheck . "0.15")
    412   :safe #'numberp)
    413 
    414 (defcustom flycheck-display-errors-function #'flycheck-display-error-messages
    415   "Function to display error messages.
    416 
    417 If set to a function, call the function with the list of errors
    418 to display as single argument.  Each error is an instance of the
    419 `flycheck-error' struct.
    420 
    421 If set to nil, do not display errors at all."
    422   :group 'flycheck
    423   :type '(choice (const :tag "Display error messages"
    424                         flycheck-display-error-messages)
    425                  (const :tag "Display error messages only if no error list"
    426                         flycheck-display-error-messages-unless-error-list)
    427                  (function :tag "Error display function"))
    428   :package-version '(flycheck . "0.13")
    429   :risky t)
    430 
    431 (defcustom flycheck-clear-displayed-errors-function #'flycheck-clear-displayed-error-messages
    432   "Function to hide error message displayed by `flycheck-display-errors-function'.
    433 
    434 If set to a function, it will be called with no arguments to
    435 clear all displayed errors at point."
    436   :group 'flycheck
    437   :type '(choice (const :tag "Clear displayed error messages"
    438                         flycheck-clear-displayed-error-messages)
    439                  (function :tag "Clear displayed errors function"))
    440   :package-version '(flycheck . "34.2")
    441   :risky t)
    442 
    443 (defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages
    444   "Function to compute the contents of the error tooltips.
    445 
    446 If set to a function, call the function with the list of errors
    447 to display as single argument.  Each error is an instance of the
    448 `flycheck-error' struct.  The function is used to set the
    449 help-echo property of flycheck error overlays.  It should return
    450 a string, which is displayed when the user hovers over an error
    451 or presses \\[display-local-help].
    452 
    453 If set to nil, do not show error tooltips."
    454   :group 'flycheck
    455   :type '(choice (const :tag "Concatenate error messages to form a tooltip"
    456                         flycheck-help-echo-all-error-messages)
    457                  (function :tag "Help echo function"))
    458   :package-version '(flycheck . "0.25")
    459   :risky t)
    460 
    461 (defcustom flycheck-command-wrapper-function #'identity
    462   "Function to modify checker commands before execution.
    463 
    464 The value of this option is a function which is given a list
    465 containing the full command of a syntax checker after
    466 substitution through `flycheck-substitute-argument' but before
    467 execution.  The function may return a new command for Flycheck to
    468 execute.
    469 
    470 The default value is `identity' which does not change the
    471 command.  You may provide your own function to run Flycheck
    472 commands through `bundle exec', `nix-shell' or similar wrappers."
    473   :group 'flycheck
    474   :type '(choice (const :tag "Do not modify commands" identity)
    475                  (function :tag "Modify command with a custom function"))
    476   :package-version '(flycheck . "0.25")
    477   :risky t)
    478 
    479 (defcustom flycheck-executable-find #'flycheck-default-executable-find
    480   "Function to search for executables.
    481 
    482 The value of this option is a function which is given the name or
    483 path of an executable and shall return the full path to the
    484 executable, or nil if the executable does not exit.
    485 
    486 The default is `flycheck-default-executable-find', which searches
    487 variable `exec-path' when given a command name, and resolves
    488 paths to absolute ones.  You can customize this option to search
    489 for checkers in other environments such as bundle or NixOS
    490 sandboxes."
    491   :group 'flycheck
    492   :type '(choice
    493           (const :tag "Search executables in `exec-path'"
    494                  flycheck-default-executable-find)
    495           (function :tag "Search executables with a custom function"))
    496   :package-version '(flycheck . "32")
    497   :risky t)
    498 
    499 (defun flycheck-default-executable-find (executable)
    500   "Resolve EXECUTABLE to a full path.
    501 
    502 Like `executable-find', but supports relative paths.
    503 
    504 Attempts invoking `executable-find' first; if that returns nil,
    505 and EXECUTABLE contains a directory component, expands to a full
    506 path and tries invoking `executable-find' again."
    507   ;; file-name-directory returns non-nil iff the given path has a
    508   ;; directory component.
    509   (or
    510    (executable-find executable)
    511    (when (file-name-directory executable)
    512      (executable-find (expand-file-name executable)))))
    513 
    514 (defcustom flycheck-indication-mode 'left-fringe
    515   "The indication mode for Flycheck errors.
    516 
    517 This variable controls how Flycheck indicates errors in buffers.
    518 May be `left-fringe', `right-fringe', `left-margin',
    519 `right-margin', or nil.
    520 
    521 If set to `left-fringe' or `right-fringe', indicate errors via
    522 icons in the left and right fringe respectively.  If set to
    523 `left-margin' or `right-margin', use the margins instead.
    524 
    525 If set to nil, do not indicate errors and warnings, but just
    526 highlight them according to `flycheck-highlighting-mode'."
    527   :group 'flycheck
    528   :type '(choice (const :tag "Indicate in the left fringe" left-fringe)
    529                  (const :tag "Indicate in the right fringe" right-fringe)
    530                  (const :tag "Indicate in the left margin" left-margin)
    531                  (const :tag "Indicate in the right margin" right-margin)
    532                  (const :tag "Do not indicate" nil))
    533   :safe #'symbolp)
    534 
    535 (defcustom flycheck-highlighting-mode 'symbols
    536   "The highlighting mode for Flycheck errors and warnings.
    537 
    538 The highlighting mode controls how Flycheck highlights errors in
    539 buffers when a checker only reports the starting position of an
    540 error.  The following modes are known:
    541 
    542 `columns'
    543      Highlight a single character.  If the error does not have a column,
    544      highlight the whole line.
    545 
    546 `symbols'
    547      Highlight a full symbol if there is any, otherwise behave like `columns'.
    548      This is the default.
    549 
    550 `sexps'
    551      Highlight a full expression, if there is any, otherwise behave like
    552      `columns'.  Note that this mode can be *very* slow in some major modes.
    553 
    554 `lines'
    555      Highlight the whole line.
    556 
    557 nil
    558      Do not highlight errors at all.  However, errors will still
    559      be reported in the mode line and in error message popups,
    560      and indicated according to `flycheck-indication-mode'."
    561   :group 'flycheck
    562   :type '(choice (const :tag "Highlight columns only" columns)
    563                  (const :tag "Highlight symbols" symbols)
    564                  (const :tag "Highlight expressions" sexps)
    565                  (const :tag "Highlight whole lines" lines)
    566                  (const :tag "Do not highlight errors" nil))
    567   :package-version '(flycheck . "0.14")
    568   :safe #'symbolp)
    569 
    570 (defvar flycheck-current-errors)
    571 (defun flycheck-refresh-fringes-and-margins ()
    572   "Refresh fringes and margins of all windows displaying the current buffer.
    573 
    574 If any errors are currently shown, launch a new check, to adjust
    575 to a potential new indication mode."
    576   (dolist (win (get-buffer-window-list))
    577     (set-window-margins win left-margin-width right-margin-width)
    578     (set-window-fringes win left-fringe-width right-fringe-width))
    579   (when flycheck-current-errors
    580     (flycheck-buffer)))
    581 
    582 (defun flycheck-set-indication-mode (&optional mode)
    583   "Set `flycheck-indication-mode' to MODE and adjust margins and fringes.
    584 
    585 When MODE is nil, adjust window parameters without changing the
    586 mode.  This function can be useful as a `flycheck-mode-hook',
    587 especially if you use margins only in Flycheck buffers.
    588 
    589 When MODE is `left-margin', the left fringe is reduced to 1 pixel
    590 to save space."
    591   (interactive (list (intern (completing-read
    592                               "Mode: " '("left-fringe" "right-fringe"
    593                                          "left-margin" "right-margin")
    594                               nil t nil nil
    595                               (prin1-to-string flycheck-indication-mode)))))
    596   (setq mode (or mode flycheck-indication-mode))
    597   (pcase mode
    598     ((or `left-fringe `right-fringe)
    599      (setq left-fringe-width 8 right-fringe-width 8
    600            left-margin-width 0 right-margin-width 0))
    601     (`left-margin
    602      (setq left-fringe-width 1 right-fringe-width 8
    603            left-margin-width 1 right-margin-width 0))
    604     (`right-margin
    605      (setq left-fringe-width 8 right-fringe-width 8
    606            left-margin-width 0 right-margin-width 1))
    607     (_ (user-error "Invalid indication mode")))
    608   (setq-local flycheck-indication-mode mode)
    609   (flycheck-refresh-fringes-and-margins))
    610 
    611 (define-widget 'flycheck-highlighting-style 'lazy
    612   "A value for `flycheck-highlighting-style'."
    613   :offset 2
    614   :format "%t: Use %v"
    615   :type '(choice
    616           :format "%[Value Menu%] %v"
    617           (const :tag "no highlighting" nil)
    618           (const :tag "a face indicating the error level" level-face)
    619           (list :tag "a pair of delimiters"
    620                 (const :format "" delimiters)
    621                 (string :tag "Before")
    622                 (string :tag "After"))
    623           (list :tag "a conditional mix of styles"
    624                 (const :format "" conditional)
    625                 (integer :tag "Up to this many lines")
    626                 (flycheck-highlighting-style :format "Use %v")
    627                 (flycheck-highlighting-style :format "Otherwise, use %v"))))
    628 
    629 (defun flycheck--make-highlighting-delimiter (char)
    630   "Make a highlighting bracket symbol by repeating CHAR twice."
    631   (compose-chars ?\s
    632                  ;; '(Bl . Br) ?\s
    633                  '(Bc Br 30 0) char
    634                  '(Bc Bl -30 0) char))
    635 
    636 (defcustom flycheck-highlighting-style
    637   `(conditional 4 level-face (delimiters "" ""))
    638   "The highlighting style for Flycheck errors and warnings.
    639 
    640 The highlighting style controls how Flycheck highlights error
    641 regions in buffers.  The following styles are supported:
    642 
    643 nil
    644      Do not highlight errors.  Same as setting
    645      `flycheck-highlighting-mode' to nil.
    646 
    647 `level-face'
    648      Chose a face depending on the severity of the error, and
    649      apply it to the whole error text.  See also the
    650      `flycheck-define-error-level' and `flycheck-error',
    651      `flycheck-warning', and `flycheck-info' faces.
    652 
    653 \(`delimiters' BEFORE AFTER)
    654      Draw delimiters on each side of the error.  BEFORE and AFTER
    655      indicate which delimiters to use.  If they are strings, they
    656      are used as-is.  If they are characters, they are repeated
    657      twice and composed into a single character.  Delimiters use
    658      the fringe face corresponding to the severity of each error,
    659      as well as the `flycheck-error-delimiter' face.  Delimited
    660      text has the `flycheck-delimited-error' face.
    661 
    662 \(`conditional' NLINES S1 S2)
    663      Use style S1 for errors spanning up to NLINES lines, and
    664      style S2 otherwise.
    665 
    666 See also `flycheck-highlighting-mode' and
    667 `flycheck-indication-mode'."
    668   :group 'flycheck
    669   :type 'flycheck-highlighting-style
    670   :package-version '(flycheck . "32")
    671   :safe t)
    672 
    673 (defcustom flycheck-check-syntax-automatically '(save
    674                                                  idle-change
    675                                                  new-line
    676                                                  mode-enabled)
    677   "When Flycheck should check syntax automatically.
    678 
    679 This variable is a list of events that may trigger syntax checks.
    680 The following events are known:
    681 
    682 `save'
    683      Check syntax immediately after the buffer was saved.
    684 
    685 `idle-change'
    686      Check syntax a short time (see `flycheck-idle-change-delay')
    687      after the last change to the buffer.
    688 
    689 `idle-buffer-switch'
    690      Check syntax a short time (see `flycheck-idle-buffer-switch-delay')
    691      after the user switches to a buffer.
    692 
    693 `new-line'
    694      Check syntax immediately after a new line was inserted into
    695      the buffer.
    696 
    697 `mode-enabled'
    698      Check syntax immediately when variable `flycheck-mode' is
    699      non-nil.
    700 
    701 Flycheck performs a syntax checks only on events, which are
    702 contained in this list.  For instance, if the value of this
    703 variable is `(mode-enabled save)', Flycheck will only check if
    704 the mode is enabled or the buffer was saved, but never after
    705 changes to the buffer contents.
    706 
    707 If nil, never check syntax automatically.  In this case, use
    708 `flycheck-buffer' to start a syntax check manually."
    709   :group 'flycheck
    710   :type '(set (const :tag "After the buffer was saved" save)
    711               (const :tag "After the buffer was changed and idle" idle-change)
    712               (const
    713                :tag "After switching the current buffer" idle-buffer-switch)
    714               (const :tag "After a new line was inserted" new-line)
    715               (const :tag "After `flycheck-mode' was enabled" mode-enabled))
    716   :package-version '(flycheck . "0.12")
    717   :safe #'flycheck-symbol-list-p)
    718 
    719 (defcustom flycheck-idle-change-delay 0.5
    720   "How many seconds to wait after a change before checking syntax.
    721 
    722 After the buffer was changed, Flycheck will wait as many seconds
    723 as the value of this variable before starting a syntax check.  If
    724 the buffer is modified during this time, Flycheck will wait
    725 again.
    726 
    727 This variable has no effect, if `idle-change' is not contained in
    728 `flycheck-check-syntax-automatically'."
    729   :group 'flycheck
    730   :type 'number
    731   :package-version '(flycheck . "0.13")
    732   :safe #'numberp)
    733 
    734 (defcustom flycheck-idle-buffer-switch-delay 0.5
    735   "How many seconds to wait after switching buffers before checking syntax.
    736 
    737 After the user switches to a new buffer, Flycheck will wait as
    738 many seconds as the value of this variable before starting a
    739 syntax check.  If the user switches to another buffer during this
    740 time, whether a syntax check is still performed depends on the
    741 value of `flycheck-buffer-switch-check-intermediate-buffers'.
    742 
    743 This variable has no effect if `idle-buffer-switch' is not
    744 contained in `flycheck-check-syntax-automatically'."
    745   :group 'flycheck
    746   :type 'number
    747   :package-version '(flycheck . "32")
    748   :safe #'numberp)
    749 
    750 (defcustom flycheck-buffer-switch-check-intermediate-buffers nil
    751   "Whether to check syntax in a buffer you only visit briefly.
    752 
    753 If nil, then when you switch to a buffer but switch to another
    754 buffer before the syntax check is performed, then the check is
    755 canceled.  If non-nil, then syntax checks due to switching
    756 buffers are always performed.  This only affects buffer switches
    757 that happen less than `flycheck-idle-buffer-switch-delay' seconds
    758 apart.
    759 
    760 This variable has no effect if `idle-buffer-switch' is not
    761 contained in `flycheck-check-syntax-automatically'."
    762   :group 'flycheck
    763   :type 'boolean
    764   :package-version '(flycheck . "32")
    765   :safe #'booleanp)
    766 
    767 (defcustom flycheck-standard-error-navigation t
    768   "Whether to support error navigation with `next-error'.
    769 
    770 If non-nil, enable navigation of Flycheck errors with
    771 `next-error', `previous-error' and `first-error'.  Otherwise,
    772 these functions just navigate errors from compilation modes.
    773 
    774 Flycheck error navigation with `flycheck-next-error',
    775 `flycheck-previous-error' and `flycheck-first-error' is always
    776 enabled, regardless of the value of this variable.
    777 
    778 Note that this setting only takes effect when variable
    779 `flycheck-mode' is non-nil.  Changing it will not affect buffers
    780 where variable `flycheck-mode' is already non-nil."
    781   :group 'flycheck
    782   :type 'boolean
    783   :package-version '(flycheck . "0.15")
    784   :safe #'booleanp)
    785 
    786 (define-widget 'flycheck-minimum-level 'lazy
    787   "A radio-type choice of minimum error levels.
    788 
    789 See `flycheck-navigation-minimum-level' and
    790 `flycheck-error-list-minimum-level'."
    791   :type '(radio (const :tag "All locations" nil)
    792                 (const :tag "Informational messages" info)
    793                 (const :tag "Warnings" warning)
    794                 (const :tag "Errors" error)
    795                 (symbol :tag "Custom error level")))
    796 
    797 (defcustom flycheck-navigation-minimum-level nil
    798   "The minimum level of errors to navigate.
    799 
    800 If set to an error level, only navigate errors whose error level
    801 is at least as severe as this one.  If nil, navigate all errors."
    802   :group 'flycheck
    803   :type 'flycheck-minimum-level
    804   :safe #'flycheck-error-level-p
    805   :package-version '(flycheck . "0.21"))
    806 
    807 (defcustom flycheck-error-list-minimum-level nil
    808   "The minimum level of errors to display in the error list.
    809 
    810 If set to an error level, only display errors whose error level
    811 is at least as severe as this one in the error list.  If nil,
    812 display all errors.
    813 
    814 This is the default level, used when the error list is opened.
    815 You can temporarily change the level using
    816 \\[flycheck-error-list-set-filter], or reset it to this value
    817 using \\[flycheck-error-list-reset-filter]."
    818   :group 'flycheck
    819   :type 'flycheck-minimum-level
    820   :safe #'flycheck-error-level-p
    821   :package-version '(flycheck . "0.24"))
    822 
    823 (defcustom flycheck-relevant-error-other-file-minimum-level 'error
    824   "The minimum level of errors from other files to display in this buffer.
    825 
    826 If set to an error level, only display errors from other files
    827 whose error level is at least as severe as this one.  If nil,
    828 display all errors from other files."
    829   :group 'flycheck
    830   :type 'flycheck-minimum-level
    831   :safe #'flycheck-error-level-p
    832   :package-version '(flycheck . "32"))
    833 
    834 (defcustom flycheck-relevant-error-other-file-show t
    835   "Whether to show errors from other files."
    836   :group 'flycheck
    837   :type 'boolean
    838   :package-version '(flycheck . "32")
    839   :safe #'booleanp)
    840 
    841 (defcustom flycheck-completing-read-function #'completing-read
    842   "Function to read from minibuffer with completion.
    843 
    844 The function must be compatible to the built-in `completing-read'
    845 function."
    846   :group 'flycheck
    847   :type '(choice (const :tag "Default" completing-read)
    848                  (const :tag "IDO" ido-completing-read)
    849                  (function :tag "Custom function"))
    850   :risky t
    851   :package-version '(flycheck . "26"))
    852 
    853 (defcustom flycheck-temp-prefix "flycheck"
    854   "Prefix for temporary files created by Flycheck."
    855   :group 'flycheck
    856   :type 'string
    857   :package-version '(flycheck . "0.19")
    858   :risky t)
    859 
    860 (defcustom flycheck-mode-hook nil
    861   "Hooks to run after command `flycheck-mode' is toggled."
    862   :group 'flycheck
    863   :type 'hook
    864   :risky t)
    865 
    866 (defcustom flycheck-after-syntax-check-hook nil
    867   "Functions to run after each syntax check.
    868 
    869 This hook is run after a syntax check was finished.
    870 
    871 At this point, *all* chained checkers were run, and all errors
    872 were parsed, highlighted and reported.  The variable
    873 `flycheck-current-errors' contains all errors from all syntax
    874 checkers run during the syntax check, so you can apply any error
    875 analysis functions.
    876 
    877 Note that this hook does *not* run after each individual syntax
    878 checker in the syntax checker chain, but only after the *last
    879 checker*.
    880 
    881 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    882   :group 'flycheck
    883   :type 'hook
    884   :risky t)
    885 
    886 (defcustom flycheck-before-syntax-check-hook nil
    887   "Functions to run before each syntax check.
    888 
    889 This hook is run right before a syntax check starts.
    890 
    891 Error information from the previous syntax check is *not*
    892 cleared before this hook runs.
    893 
    894 Note that this hook does *not* run before each individual syntax
    895 checker in the syntax checker chain, but only before the *first
    896 checker*.
    897 
    898 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    899   :group 'flycheck
    900   :type 'hook
    901   :risky t)
    902 
    903 (defcustom flycheck-syntax-check-failed-hook nil
    904   "Functions to run if a syntax check failed.
    905 
    906 This hook is run whenever an error occurs during Flycheck's
    907 internal processing.  No information about the error is given to
    908 this hook.
    909 
    910 You should use this hook to conduct additional cleanup actions
    911 when Flycheck failed.
    912 
    913 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    914   :group 'flycheck
    915   :type 'hook
    916   :risky t)
    917 
    918 (defcustom flycheck-status-changed-functions nil
    919   "Functions to run if the Flycheck status changed.
    920 
    921 This hook is run whenever the status of Flycheck changes.  Each
    922 hook function takes the status symbol as single argument, as
    923 given to `flycheck-report-status', which see.
    924 
    925 This variable is an abnormal hook.  See Info
    926 node `(elisp)Hooks'."
    927   :group 'flycheck
    928   :type 'hook
    929   :risky t
    930   :package-version '(flycheck . "0.20"))
    931 
    932 (defcustom flycheck-error-list-after-refresh-hook nil
    933   "Functions to run after the error list was refreshed.
    934 
    935 This hook is run whenever the error list is refreshed.
    936 
    937 This variable is a normal hook.  See Info node `(elisp)Hooks'."
    938   :group 'flycheck
    939   :type 'hook
    940   :risky t
    941   :package-version '(flycheck . "0.21"))
    942 
    943 (defface flycheck-error-delimiter
    944   `((t))
    945   "Flycheck face for errors spanning multiple lines.
    946 
    947 See `flycheck-highlighting-style' for details on when this face
    948 is used."
    949   :package-version '(flycheck . "32")
    950   :group 'flycheck-faces)
    951 
    952 (defface flycheck-delimited-error
    953   `((t))
    954   "Flycheck face for errors spanning multiple lines.
    955 
    956 See `flycheck-highlighting-style' for details on when this face
    957 is used."
    958   :package-version '(flycheck . "32")
    959   :group 'flycheck-faces)
    960 
    961 (defface flycheck-error
    962   '((((supports :underline (:style wave)))
    963      :underline (:style wave :color "Red1"))
    964     (t
    965      :underline t :inherit error))
    966   "Flycheck face for errors."
    967   :package-version '(flycheck . "0.13")
    968   :group 'flycheck-faces)
    969 
    970 (defface flycheck-warning
    971   '((((supports :underline (:style wave)))
    972      :underline (:style wave :color "DarkOrange"))
    973     (t
    974      :underline t :inherit warning))
    975   "Flycheck face for warnings."
    976   :package-version '(flycheck . "0.13")
    977   :group 'flycheck-faces)
    978 
    979 (defface flycheck-info
    980   '((((supports :underline (:style wave)))
    981      :underline (:style wave :color "ForestGreen"))
    982     (t
    983      :underline t :inherit success))
    984   "Flycheck face for informational messages."
    985   :package-version '(flycheck . "0.15")
    986   :group 'flycheck-faces)
    987 
    988 (defface flycheck-fringe-error
    989   '((t :inherit error))
    990   "Flycheck face for fringe error indicators."
    991   :package-version '(flycheck . "0.13")
    992   :group 'flycheck-faces)
    993 
    994 (defface flycheck-fringe-warning
    995   '((t :inherit warning))
    996   "Flycheck face for fringe warning indicators."
    997   :package-version '(flycheck . "0.13")
    998   :group 'flycheck-faces)
    999 
   1000 (defface flycheck-fringe-info
   1001   ;; Semantically `success' is probably not the right face, but it looks nice as
   1002   ;; a base face
   1003   '((t :inherit success))
   1004   "Flycheck face for fringe info indicators."
   1005   :package-version '(flycheck . "0.15")
   1006   :group 'flycheck-faces)
   1007 
   1008 (defface flycheck-error-list-error
   1009   '((t :inherit error))
   1010   "Flycheck face for error messages in the error list."
   1011   :package-version '(flycheck . "0.16")
   1012   :group 'flycheck-faces)
   1013 
   1014 (defface flycheck-error-list-warning
   1015   '((t :inherit warning))
   1016   "Flycheck face for warning messages in the error list."
   1017   :package-version '(flycheck . "0.16")
   1018   :group 'flycheck-faces)
   1019 
   1020 (defface flycheck-error-list-info
   1021   '((t :inherit success))
   1022   "Flycheck face for info messages in the error list."
   1023   :package-version '(flycheck . "0.16")
   1024   :group 'flycheck-faces)
   1025 
   1026 (defface flycheck-error-list-line-number
   1027   '((t))
   1028   "Face for line numbers in the error list."
   1029   :group 'flycheck-faces
   1030   :package-version '(flycheck . "0.16"))
   1031 
   1032 (defface flycheck-error-list-column-number
   1033   '((t))
   1034   "Face for line numbers in the error list."
   1035   :group 'flycheck-faces
   1036   :package-version '(flycheck . "0.16"))
   1037 
   1038 (defface flycheck-error-list-filename
   1039   '((t :inherit mode-line-buffer-id :bold nil))
   1040   "Face for filenames in the error list."
   1041   :group 'flycheck-faces
   1042   :package-version '(flycheck . "32"))
   1043 
   1044 (defface flycheck-error-list-id
   1045   '((t :inherit font-lock-type-face))
   1046   "Face for the error ID in the error list."
   1047   :group 'flycheck-faces
   1048   :package-version '(flycheck . "0.22"))
   1049 
   1050 (defface flycheck-error-list-id-with-explainer
   1051   '((t :inherit flycheck-error-list-id
   1052        :box (:style released-button)))
   1053   "Face for the error ID in the error list, for errors that have an explainer."
   1054   :group 'flycheck-faces
   1055   :package-version '(flycheck . "30"))
   1056 
   1057 (defface flycheck-error-list-checker-name
   1058   '((t :inherit font-lock-function-name-face))
   1059   "Face for the syntax checker name in the error list."
   1060   :group 'flycheck-faces
   1061   :package-version '(flycheck . "0.21"))
   1062 
   1063 (defface flycheck-error-list-error-message
   1064   '((t))
   1065   "Face for the error message in the error list."
   1066   :group 'flycheck-faces
   1067   :package-version '(flycheck . "33"))
   1068 
   1069 (defface flycheck-error-list-highlight
   1070   '((t :bold t))
   1071   "Flycheck face to highlight errors in the error list."
   1072   :package-version '(flycheck . "0.15")
   1073   :group 'flycheck-faces)
   1074 
   1075 (defface flycheck-verify-select-checker
   1076   '((t :box (:style released-button)))
   1077   "Flycheck face for the `select' button in the verify setup buffer."
   1078   :package-version '(flycheck . "32")
   1079   :group 'flycheck-faces)
   1080 
   1081 (defvar flycheck-command-map
   1082   (let ((map (make-sparse-keymap)))
   1083     (define-key map "c"         #'flycheck-buffer)
   1084     (define-key map "C"         #'flycheck-clear)
   1085     (define-key map (kbd "C-c") #'flycheck-compile)
   1086     (define-key map "n"         #'flycheck-next-error)
   1087     (define-key map "p"         #'flycheck-previous-error)
   1088     (define-key map "l"         #'flycheck-list-errors)
   1089     (define-key map (kbd "C-w") #'flycheck-copy-errors-as-kill)
   1090     (define-key map "s"         #'flycheck-select-checker)
   1091     (define-key map "?"         #'flycheck-describe-checker)
   1092     (define-key map "h"         #'flycheck-display-error-at-point)
   1093     (define-key map "e"         #'flycheck-explain-error-at-point)
   1094     (define-key map "H"         #'display-local-help)
   1095     (define-key map "i"         #'flycheck-manual)
   1096     (define-key map "V"         #'flycheck-version)
   1097     (define-key map "v"         #'flycheck-verify-setup)
   1098     (define-key map "x"         #'flycheck-disable-checker)
   1099     map)
   1100   "Keymap of Flycheck interactive commands.")
   1101 
   1102 (defcustom flycheck-keymap-prefix (kbd "C-c !")
   1103   "Prefix for key bindings of Flycheck.
   1104 
   1105 Changing this variable outside Customize does not have any
   1106 effect.  To change the keymap prefix from Lisp, you need to
   1107 explicitly re-define the prefix key:
   1108 
   1109     (define-key flycheck-mode-map flycheck-keymap-prefix nil)
   1110     (setq flycheck-keymap-prefix (kbd \"C-c f\"))
   1111     (define-key flycheck-mode-map flycheck-keymap-prefix
   1112                 flycheck-command-map)
   1113 
   1114 Please note that Flycheck's manual documents the default
   1115 keybindings.  Changing this variable is at your own risk."
   1116   :group 'flycheck
   1117   :package-version '(flycheck . "0.19")
   1118   :type 'string
   1119   :risky t
   1120   :set
   1121   (lambda (variable key)
   1122     (when (and (boundp variable) (boundp 'flycheck-mode-map))
   1123       (define-key flycheck-mode-map (symbol-value variable) nil)
   1124       (define-key flycheck-mode-map key flycheck-command-map))
   1125     (set-default variable key)))
   1126 
   1127 (defcustom flycheck-mode-line '(:eval (flycheck-mode-line-status-text))
   1128   "Mode line lighter for Flycheck.
   1129 
   1130 The value of this variable is a mode line template as in
   1131 `mode-line-format'.  See Info Node `(elisp)Mode Line Format' for
   1132 more information.  Note that it should contain a _single_ mode
   1133 line construct only.
   1134 
   1135 Customize this variable to change how Flycheck reports its status
   1136 in the mode line.  You may use `flycheck-mode-line-status-text'
   1137 to obtain a human-readable status text, including an
   1138 error/warning count.
   1139 
   1140 You may also assemble your own status text.  The current status
   1141 of Flycheck is available in `flycheck-last-status-change'.  The
   1142 errors in the current buffer are stored in
   1143 `flycheck-current-errors', and the function
   1144 `flycheck-count-errors' may be used to obtain the number of
   1145 errors grouped by error level.
   1146 
   1147 Set this variable to nil to disable the mode line completely."
   1148   :group 'flycheck
   1149   :type 'sexp
   1150   :risky t
   1151   :package-version '(flycheck . "0.20"))
   1152 
   1153 (defcustom flycheck-mode-line-color t
   1154   "Use colors for Flycheck mode line status."
   1155   :group 'flycheck
   1156   :type 'boolean
   1157   :package-version '(flycheck . "35"))
   1158 
   1159 (defcustom flycheck-mode-line-prefix "FlyC"
   1160   "Base mode line lighter for Flycheck.
   1161 
   1162 This will have an effect only with the default
   1163 `flycheck-mode-line'.
   1164 
   1165 If you've customized `flycheck-mode-line' then the customized
   1166 function must be updated to use this variable."
   1167   :group 'flycheck
   1168   :type 'string
   1169   :package-version '(flycheck . "26"))
   1170 
   1171 (defcustom flycheck-mode-success-indicator ":0"
   1172   "Success indicator appended to `flycheck-mode-line-prefix'."
   1173   :group 'flycheck
   1174   :type 'string
   1175   :package-version '(flycheck . "35"))
   1176 
   1177 (defcustom flycheck-error-list-mode-line
   1178   `(,(propertized-buffer-identification "%12b")
   1179     " for buffer "
   1180     (:eval (flycheck-error-list-propertized-source-name))
   1181     (:eval (flycheck-error-list-mode-line-filter-indicator)))
   1182   "Mode line construct for Flycheck error list.
   1183 
   1184 The value of this variable is a mode line template as in
   1185 `mode-line-format', to be used as
   1186 `mode-line-buffer-identification' in `flycheck-error-list-mode'.
   1187 See Info Node `(elisp)Mode Line Format' for more information.
   1188 
   1189 Customize this variable to change how the error list appears in
   1190 the mode line.  The default shows the name of the buffer and the
   1191 name of the source buffer, i.e. the buffer whose errors are
   1192 currently listed."
   1193   :group 'flycheck
   1194   :type 'sexp
   1195   :risky t
   1196   :package-version '(flycheck . "0.20"))
   1197 
   1198 (defcustom flycheck-global-modes t
   1199   "Modes for which option `flycheck-mode' is turned on.
   1200 
   1201 If t, Flycheck Mode is turned on for all major modes.  If a list,
   1202 Flycheck Mode is turned on for all `major-mode' symbols in that
   1203 list.  If the `car' of the list is `not', Flycheck Mode is turned
   1204 on for all `major-mode' symbols _not_ in that list.  If nil,
   1205 Flycheck Mode is never turned on by command
   1206 `global-flycheck-mode'.
   1207 
   1208 Note that Flycheck is never turned on for modes whose
   1209 `mode-class' property is `special' (see Info node `(elisp)Major
   1210 Mode Conventions'), regardless of the value of this option.
   1211 
   1212 Only has effect when variable `global-flycheck-mode' is non-nil."
   1213   :group 'flycheck
   1214   :type '(choice (const :tag "none" nil)
   1215                  (const :tag "all" t)
   1216                  (set :menu-tag "mode specific" :tag "modes"
   1217                       :value (not)
   1218                       (const :tag "Except" not)
   1219                       (repeat :inline t (symbol :tag "mode"))))
   1220   :risky t
   1221   :package-version '(flycheck . "0.23"))
   1222 
   1223 ;; Add built-in functions to our hooks, via `add-hook', to make sure that our
   1224 ;; functions are really present, even if the variable was implicitly defined by
   1225 ;; another call to `add-hook' that occurred before Flycheck was loaded.  See
   1226 ;; https://lists.gnu.org/archive/html/emacs-devel/2015-02/msg01271.html for why
   1227 ;; we don't initialize the hook variables right away.  We append our own
   1228 ;; functions, because a user likely expects that their functions come first,
   1229 ;; even if they added them before Flycheck was loaded.
   1230 (dolist (hook (list #'flycheck-locate-config-file-by-path
   1231                     #'flycheck-locate-config-file-ancestor-directories
   1232                     #'flycheck-locate-config-file-home))
   1233   (add-hook 'flycheck-locate-config-file-functions hook 'append))
   1234 
   1235 (add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append)
   1236 
   1237 
   1238 ;;; Global Flycheck menu
   1239 (defvar flycheck-mode-menu-map
   1240   (easy-menu-create-menu
   1241    "Syntax Checking"
   1242    '(["Enable on-the-fly syntax checking" flycheck-mode
   1243       :style toggle :selected flycheck-mode
   1244       :enable (or flycheck-mode
   1245                   ;; Don't let users toggle the mode if there is no syntax
   1246                   ;; checker for this buffer
   1247                   (seq-find #'flycheck-checker-supports-major-mode-p
   1248                             flycheck-checkers))]
   1249      ["Check current buffer" flycheck-buffer flycheck-mode]
   1250      ["Clear errors in buffer" flycheck-clear t]
   1251      ["Run checker as compile command" flycheck-compile flycheck-mode]
   1252      "---"
   1253      ["Go to next error" flycheck-next-error flycheck-mode]
   1254      ["Go to previous error" flycheck-previous-error flycheck-mode]
   1255      ["Show all errors" flycheck-list-errors flycheck-mode]
   1256      "---"
   1257      ["Copy messages at point" flycheck-copy-errors-as-kill
   1258       (flycheck-overlays-at (point))]
   1259      ["Explain error at point" flycheck-explain-error-at-point]
   1260      "---"
   1261      ["Select syntax checker" flycheck-select-checker flycheck-mode]
   1262      ["Disable syntax checker" flycheck-disable-checker flycheck-mode]
   1263      ["Set executable of syntax checker" flycheck-set-checker-executable
   1264       flycheck-mode]
   1265      "---"
   1266      ["Describe syntax checker" flycheck-describe-checker t]
   1267      ["Verify setup" flycheck-verify-setup t]
   1268      ["Show Flycheck version" flycheck-version t]
   1269      ["Flycheck quick help" flycheck-quick-help t]
   1270      ["Read the Flycheck manual" flycheck-manual t]))
   1271   "Menu of command `flycheck-mode'.")
   1272 
   1273 (easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking")
   1274 
   1275 
   1276 
   1277 (defconst flycheck-version "35.0-snapshot"
   1278   "The current version of Flycheck.
   1279 
   1280 Should be kept in sync with the package version metadata.
   1281 Used only when `package-get-function' is not available
   1282 or fails.")
   1283 
   1284 (defun flycheck--pkg-version ()
   1285   "Extract FLYCHECK's package version from its package metadata."
   1286   ;; Use `cond' below to avoid a compiler unused return value warning
   1287   ;; when `package-get-version' returns nil. See #3181.
   1288   (cond ((fboundp 'package-get-version)
   1289          (package-get-version))
   1290         ((fboundp 'pkg-info-version-info)
   1291          (pkg-info-version-info 'flycheck))
   1292         (t
   1293          flycheck-version)))
   1294 
   1295 ;;; Version information, manual and loading of Flycheck
   1296 (defun flycheck-version (&optional show-version)
   1297   "Get the Flycheck version as string.
   1298 
   1299 If called interactively or if SHOW-VERSION is non-nil, show the
   1300 version in the echo area and the messages buffer.
   1301 
   1302 The returned string includes both, the version from package.el
   1303 and the library version, if both a present and different.
   1304 
   1305 If the version number could not be determined, signal an error,
   1306 if called interactively, or if SHOW-VERSION is non-nil, otherwise
   1307 just return nil."
   1308   (interactive (list t))
   1309   (let ((version (flycheck--pkg-version)))
   1310     (when show-version
   1311       (message "Flycheck version: %s" version))
   1312     version))
   1313 
   1314 (defun flycheck-unload-function ()
   1315   "Unload function for Flycheck."
   1316   (global-flycheck-mode -1)
   1317   (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map))
   1318   (remove-hook 'kill-emacs-hook #'flycheck-global-teardown)
   1319   (setq find-function-regexp-alist
   1320         (assq-delete-all 'flycheck-checker find-function-regexp-alist)))
   1321 
   1322 ;;;###autoload
   1323 (defun flycheck-manual ()
   1324   "Open the Flycheck manual."
   1325   (interactive)
   1326   (browse-url "https://www.flycheck.org"))
   1327 
   1328 ;;;###autoload
   1329 (defun flycheck-quick-help ()
   1330   "Display brief Flycheck help."
   1331   (interactive)
   1332   (with-current-buffer (get-buffer-create "*flycheck-quick-help*")
   1333     (with-help-window (current-buffer)
   1334       (flycheck-mode) ;; so that we can exapnd \\[flycheck-<function>]
   1335       (let ((help
   1336              (substitute-command-keys
   1337         "Flycheck automatically runs checks on writable files when changed.
   1338 Mode line status for the current buffer:
   1339   FlyC        Not been checked yet
   1340   FlyC*       Flycheck is running
   1341   FlyC:0      Last check resulted in no errors and no warnings
   1342   FlyC:3|5    Checker reported three errors and five warnings
   1343   FlyC-       No checker available
   1344   FlyC!       The checker crashed
   1345   FlyC.       The last syntax check was manually interrupted
   1346   FlyC?       The checker did something unexpected
   1347 
   1348 Key bindings:
   1349   \\[flycheck-buffer]     Check current buffer
   1350   \\[flycheck-clear]     Clear errors in current buffer
   1351   \\[flycheck-compile]   Run checker as compile command
   1352 
   1353   \\[flycheck-next-error]     Next error
   1354   \\[flycheck-previous-error]     Previous error
   1355   \\[flycheck-list-errors]     List all errors
   1356 
   1357   \\[flycheck-copy-errors-as-kill]   Copy error messages at point
   1358   \\[flycheck-display-error-at-point]     Explain error at point
   1359 ")))
   1360         (help-mode)
   1361         (read-only-mode 0)
   1362         (insert help)))))
   1363 
   1364 (define-obsolete-function-alias 'flycheck-info
   1365   'flycheck-manual "Flycheck 26" "Open the Flycheck manual.")
   1366 
   1367 
   1368 ;;; Utility functions
   1369 (defun flycheck-sexp-to-string (sexp)
   1370   "Convert SEXP to a string.
   1371 
   1372 Like `prin1-to-string' but ensure that the returned string
   1373 is loadable."
   1374   (let ((print-quoted t)
   1375         (print-length nil)
   1376         (print-level nil))
   1377     (prin1-to-string sexp)))
   1378 
   1379 (defun flycheck-string-to-number-safe (string)
   1380   "Safely convert STRING to a number.
   1381 
   1382 If STRING is of string type and a numeric string, convert STRING
   1383 to a number and return it.  Otherwise return nil."
   1384   (let ((number-re (rx string-start (one-or-more (any digit)) string-end)))
   1385     (when (and (stringp string) (string-match-p number-re string))
   1386       (string-to-number string))))
   1387 
   1388 (defun flycheck-string-or-nil-p (obj)
   1389   "Determine if OBJ is a string or nil."
   1390   (or (null obj) (stringp obj)))
   1391 
   1392 (defun flycheck-string-list-p (obj)
   1393   "Determine if OBJ is a list of strings."
   1394   (and (listp obj) (seq-every-p #'stringp obj)))
   1395 
   1396 (defun flycheck-string-or-string-list-p (obj)
   1397   "Determine if OBJ is a string or a list of strings."
   1398   (or (stringp obj) (flycheck-string-list-p obj)))
   1399 
   1400 (defun flycheck-symbol-list-p (obj)
   1401   "Determine if OBJ is a list of symbols."
   1402   (and (listp obj) (seq-every-p #'symbolp obj)))
   1403 
   1404 (defvar-local flycheck--file-truename-cache nil)
   1405 
   1406 (defun flycheck--file-truename (file)
   1407   "Memoize the result of `file-truename' on (directory-file-name FILE)."
   1408   ;; `file-truename' is slow, but alternatives are incomplete, so memoizing is
   1409   ;; our best bet.  See https://github.com/flycheck/flycheck/pull/1698.
   1410   (unless flycheck--file-truename-cache
   1411     (setq-local flycheck--file-truename-cache (make-hash-table :test 'equal)))
   1412   (or (gethash file flycheck--file-truename-cache)
   1413       (puthash file (file-truename (directory-file-name file))
   1414                flycheck--file-truename-cache)))
   1415 
   1416 (defun flycheck-same-files-p (file-a file-b)
   1417   "Determine whether FILE-A and FILE-B refer to the same file.
   1418 
   1419 Files are the same if (in the order checked) they are equal, or
   1420 if they resolve to the same canonical paths."
   1421   (or (string= file-a file-b)
   1422       (string= (flycheck--file-truename file-a)
   1423                (flycheck--file-truename file-b))))
   1424 
   1425 (defvar-local flycheck-temporaries nil
   1426   "Temporary files and directories created by Flycheck.")
   1427 
   1428 (defun flycheck-temp-dir-system ()
   1429   "Create a unique temporary directory.
   1430 
   1431 Use `flycheck-temp-prefix' as prefix, and add the directory to
   1432 `flycheck-temporaries'.
   1433 
   1434 Return the path of the directory"
   1435   (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory)))
   1436     (push tempdir flycheck-temporaries)
   1437     tempdir))
   1438 
   1439 (defun flycheck-temp-file-system (filename &optional suffix)
   1440   "Create a temporary file named after FILENAME.
   1441 
   1442 If FILENAME is non-nil, this function creates a temporary
   1443 directory with `flycheck-temp-dir-system', and creates a file
   1444 with the same name as FILENAME in this directory.
   1445 
   1446 Otherwise this function creates a temporary file starting with
   1447 `flycheck-temp-prefix'.  If present, SUFFIX is appended;
   1448 otherwise, a random suffix is used.  The path of the file is
   1449 added to `flycheck-temporaries'.
   1450 
   1451 Return the path of the file."
   1452   (let ((tempfile (convert-standard-filename
   1453                    (if filename
   1454                        (expand-file-name (file-name-nondirectory filename)
   1455                                          (flycheck-temp-dir-system))
   1456                      (make-temp-file flycheck-temp-prefix nil suffix)))))
   1457     (push tempfile flycheck-temporaries)
   1458     tempfile))
   1459 
   1460 (defun flycheck-temp-file-inplace (filename &optional suffix)
   1461   "Create an in-place copy of FILENAME.
   1462 
   1463 Prefix the file with `flycheck-temp-prefix' and add the path of
   1464 the file to `flycheck-temporaries'.
   1465 
   1466 If FILENAME is nil, fall back to `flycheck-temp-file-system' with
   1467 the specified SUFFIX.
   1468 
   1469 Return the path of the file."
   1470   (if filename
   1471       (let* ((tempname (format "%s_%s"
   1472                                flycheck-temp-prefix
   1473                                (file-name-nondirectory filename)))
   1474              (tempfile (convert-standard-filename
   1475                         (expand-file-name tempname
   1476                                           (file-name-directory filename)))))
   1477         (push tempfile flycheck-temporaries)
   1478         tempfile)
   1479     (flycheck-temp-file-system filename suffix)))
   1480 
   1481 (defun flycheck-temp-directory (checker)
   1482   "Return the directory where CHECKER writes temporary files.
   1483 
   1484 Return nil if the CHECKER does not write temporary files."
   1485   (let ((args (flycheck-checker-arguments checker)))
   1486     (cond
   1487      ((memq 'source args) temporary-file-directory)
   1488      ((memq 'source-inplace args)
   1489       (if buffer-file-name (file-name-directory buffer-file-name)
   1490         temporary-file-directory))
   1491      (t nil))))
   1492 
   1493 (defun flycheck-temp-files-writable-p (checker)
   1494   "Whether CHECKER can write temporary files.
   1495 
   1496 If CHECKER has `source' or `source-inplace' in its `:command',
   1497 return whether flycheck has the permissions to create the
   1498 respective temporary files.
   1499 
   1500 Return t if CHECKER does not use temporary files."
   1501   (let ((dir (flycheck-temp-directory checker)))
   1502     (or (not dir) (file-writable-p dir))))
   1503 
   1504 (defun flycheck-save-buffer-to-file (file-name)
   1505   "Save the contents of the current buffer to FILE-NAME."
   1506   (make-directory (file-name-directory file-name) t)
   1507   (let ((jka-compr-inhibit t))
   1508     (write-region nil nil file-name nil 0)))
   1509 
   1510 (defun flycheck-save-buffer-to-temp (temp-file-fn)
   1511   "Save buffer to temp file returned by TEMP-FILE-FN.
   1512 
   1513 Return the name of the temporary file."
   1514   (let ((filename (funcall temp-file-fn (buffer-file-name))))
   1515     ;; Do not flush short-lived temporary files onto disk
   1516     (let ((write-region-inhibit-fsync t))
   1517       (flycheck-save-buffer-to-file filename))
   1518     filename))
   1519 
   1520 (defun flycheck-prepend-with-option (option items &optional prepend-fn)
   1521   "Prepend OPTION to each item in ITEMS, using PREPEND-FN.
   1522 
   1523 Prepend OPTION to each item in ITEMS.
   1524 
   1525 ITEMS is a list of strings to pass to the syntax checker.  OPTION
   1526 is the option, as string.  PREPEND-FN is a function called to
   1527 prepend OPTION to each item in ITEMS.  It receives the option and
   1528 a single item from ITEMS as argument, and must return a string or
   1529 a list of strings with OPTION prepended to the item.  If
   1530 PREPEND-FN is nil or omitted, use `list'.
   1531 
   1532 Return a list of strings where OPTION is prepended to each item
   1533 in ITEMS using PREPEND-FN.  If PREPEND-FN returns a list, it is
   1534 spliced into the resulting list."
   1535   (unless (stringp option)
   1536     (error "Option %S is not a string" option))
   1537   (unless prepend-fn
   1538     (setq prepend-fn #'list))
   1539   (let ((prepend
   1540          (lambda (item)
   1541            (let ((result (funcall prepend-fn option item)))
   1542              (cond
   1543               ((and (listp result) (seq-every-p #'stringp result)) result)
   1544               ((stringp result) (list result))
   1545               (t (error "Invalid result type for option: %S" result)))))))
   1546     (apply #'append (seq-map prepend items))))
   1547 
   1548 (defun flycheck-find-in-buffer (pattern)
   1549   "Find PATTERN in the current buffer.
   1550 
   1551 Return the result of the first matching group of PATTERN, or nil,
   1552 if PATTERN did not match."
   1553   (save-excursion
   1554     (save-restriction
   1555       (widen)
   1556       (goto-char (point-min))
   1557       (when (re-search-forward pattern nil 'no-error)
   1558         (match-string-no-properties 1)))))
   1559 
   1560 (defun flycheck-buffer-empty-p (&optional buffer)
   1561   "Check whether a BUFFER is empty, defaulting to the current one."
   1562   (= (buffer-size buffer) 0))
   1563 
   1564 (defun flycheck-buffer-nonempty-p (&optional buffer)
   1565   "Check whether a BUFFER is nonempty, defaulting to the current one."
   1566   (> (buffer-size buffer) 0))
   1567 
   1568 (defun flycheck-ephemeral-buffer-p ()
   1569   "Determine whether the current buffer is an ephemeral buffer.
   1570 
   1571 See Info node `(elisp)Buffer Names' for information about
   1572 ephemeral buffers."
   1573   (string-prefix-p " " (buffer-name)))
   1574 
   1575 (defun flycheck-encrypted-buffer-p ()
   1576   "Determine whether the current buffer is an encrypted file.
   1577 
   1578 See Info node `(epa)Top' for Emacs' interface to encrypted
   1579 files."
   1580   ;; The EPA file handler sets this variable locally to remember the recipients
   1581   ;; of the encrypted file for re-encryption.  Hence, a local binding of this
   1582   ;; variable is a good indication that the buffer is encrypted.  I haven't
   1583   ;; found any better indicator anyway.
   1584   (local-variable-p 'epa-file-encrypt-to))
   1585 
   1586 (defun flycheck-autoloads-file-p ()
   1587   "Determine whether the current buffer is an autoloads file.
   1588 
   1589 Autoloads are generated by package.el during installation."
   1590   (string-suffix-p "-autoloads.el" (buffer-name)))
   1591 
   1592 (defun flycheck-in-user-emacs-directory-p (filename)
   1593   "Whether FILENAME is in `user-emacs-directory'."
   1594   (string-prefix-p (file-name-as-directory
   1595                     (flycheck--file-truename user-emacs-directory))
   1596                    (flycheck--file-truename filename)))
   1597 
   1598 (defun flycheck-safe-delete (file-or-dir)
   1599   "Safely delete FILE-OR-DIR."
   1600   (ignore-errors
   1601     (if (file-directory-p file-or-dir)
   1602         (delete-directory file-or-dir 'recursive)
   1603       (delete-file file-or-dir))))
   1604 
   1605 (defun flycheck-safe-delete-temporaries ()
   1606   "Safely delete all temp files and directories of Flycheck.
   1607 
   1608 Safely delete all files and directories listed in
   1609 `flycheck-temporaries' and set the variable's value to nil."
   1610   (seq-do #'flycheck-safe-delete flycheck-temporaries)
   1611   (setq flycheck-temporaries nil))
   1612 
   1613 (defun flycheck-rx-file-name (form)
   1614   "Translate the `(file-name)' FORM into a regular expression."
   1615   (let ((body (or (cdr form) '((minimal-match
   1616                                 (one-or-more not-newline))))))
   1617     (rx-to-string `(group-n 1 ,@body) t)))
   1618 
   1619 (defun flycheck-rx-message (form)
   1620   "Translate the `(message)' FORM into a regular expression."
   1621   (let ((body (or (cdr form) '((one-or-more not-newline)))))
   1622     (rx-to-string `(group-n 4 ,@body) t)))
   1623 
   1624 (defun flycheck-rx-id (form)
   1625   "Translate the `(id)' FORM into a regular expression."
   1626   (rx-to-string `(group-n 5 ,@(cdr form)) t))
   1627 
   1628 (defun flycheck-rx-to-string (form &optional no-group)
   1629   "Like `rx-to-string' for FORM, but with special keywords:
   1630 
   1631 `line'
   1632      matches the initial line number.
   1633 
   1634 `column'
   1635      matches the initial column number.
   1636 
   1637 `end-line'
   1638      matches the final line number.
   1639 
   1640 `end-column'
   1641      matches the final column number (exclusive).
   1642 
   1643 
   1644 `(file-name SEXP ...)'
   1645      matches the file name.  SEXP describes the file name.  If no
   1646      SEXP is given, use a default body of `(minimal-match
   1647      (one-or-more not-newline))'.
   1648 
   1649 `(message SEXP ...)'
   1650      matches the message.  SEXP constitutes the body of the
   1651      message.  If no SEXP is given, use a default body
   1652      of `(one-or-more not-newline)'.
   1653 
   1654 `(id SEXP ...)'
   1655      matches an error ID.  SEXP describes the ID.
   1656 
   1657 NO-GROUP is passed to `rx-to-string'.
   1658 
   1659 See `rx' for a complete list of all built-in `rx' forms."
   1660   (let ((rx-constituents
   1661          (append
   1662           `((file-name flycheck-rx-file-name 0 nil) ;; group 1
   1663             (line . ,(rx (group-n 2 (one-or-more digit))))
   1664             (column . ,(rx (group-n 3 (one-or-more digit))))
   1665             (message flycheck-rx-message 0 nil) ;; group 4
   1666             (id flycheck-rx-id 0 nil) ;; group 5
   1667             (end-line . ,(rx (group-n 6 (one-or-more digit))))
   1668             (end-column . ,(rx (group-n 7 (one-or-more digit)))))
   1669           rx-constituents nil)))
   1670     (rx-to-string form no-group)))
   1671 
   1672 (defun flycheck-current-load-file ()
   1673   "Get the source file currently being loaded.
   1674 
   1675 Always return the name of the corresponding source file, never
   1676 any byte-compiled file.
   1677 
   1678 Return nil, if the currently loaded file cannot be determined."
   1679   (when-let* ((this-file (cond
   1680                           (load-in-progress load-file-name)
   1681                           ((bound-and-true-p byte-compile-current-file))
   1682                           (t (buffer-file-name))))
   1683               ;; A best guess for the source file of a compiled library. Works
   1684               ;; well in most cases, and especially for ELPA packages
   1685               (source-file (concat (file-name-sans-extension this-file)
   1686                                    ".el")))
   1687     (when (file-exists-p source-file)
   1688       source-file)))
   1689 
   1690 (defun flycheck-module-root-directory (module &optional file-name)
   1691   "Get the root directory for a MODULE in FILE-NAME.
   1692 
   1693 MODULE is a qualified module name, either a string with
   1694 components separated by a dot, or as list of components.
   1695 FILE-NAME is the name of the file or directory containing the
   1696 module as string.  When nil or omitted, defaults to the return
   1697 value of function `buffer-file-name'.
   1698 
   1699 Return the root directory of the module, that is, the directory,
   1700 from which FILE-NAME can be reached by descending directories
   1701 along each part of MODULE.
   1702 
   1703 If the MODULE name does not match the directory hierarchy upwards
   1704 from FILE-NAME, return the directory containing FILE-NAME.  When
   1705 FILE-NAME is nil, return `default-directory'."
   1706   (let ((file-name (or file-name (buffer-file-name)))
   1707         (module-components (if (stringp module)
   1708                                (split-string module (rx "."))
   1709                              (copy-sequence module))))
   1710     (if (and module-components file-name)
   1711         (let ((parts (nreverse module-components))
   1712               (base-directory (directory-file-name
   1713                                (file-name-sans-extension file-name))))
   1714           (while (and parts
   1715                       (string= (file-name-nondirectory base-directory)
   1716                                (car parts)))
   1717             (pop parts)
   1718             (setq base-directory (directory-file-name
   1719                                   (file-name-directory base-directory))))
   1720           (file-name-as-directory base-directory))
   1721       (if file-name
   1722           (file-name-directory file-name)
   1723         (expand-file-name default-directory)))))
   1724 
   1725 (cl-defstruct (flycheck-line-cache
   1726                (:constructor flycheck-line-cache-new))
   1727   "Cache structure used to speed up `flycheck-goto-line'."
   1728   tick point line)
   1729 
   1730 (defvar-local flycheck--line-cache nil
   1731   "Cache used to speed ip `flycheck-goto-line'.")
   1732 
   1733 (defsubst flycheck--init-line-cache ()
   1734   "Initialize or reinitialize `flycheck--line-cache'."
   1735   (let ((tick (buffer-modified-tick)))
   1736     (if flycheck--line-cache
   1737         (unless (= (flycheck-line-cache-tick flycheck--line-cache) tick)
   1738           (setf (flycheck-line-cache-tick flycheck--line-cache) tick
   1739                 (flycheck-line-cache-point flycheck--line-cache) 1
   1740                 (flycheck-line-cache-line flycheck--line-cache) 1))
   1741       (setq-local flycheck--line-cache
   1742                   (flycheck-line-cache-new :tick tick :point 1 :line 1)))))
   1743 
   1744 (defun flycheck-goto-line (line)
   1745   "Move point to beginning of line number LINE.
   1746 
   1747 This function assumes that the current buffer is not narrowed."
   1748   (flycheck--init-line-cache)
   1749   (goto-char (flycheck-line-cache-point flycheck--line-cache))
   1750   (let ((delta (- line (flycheck-line-cache-line flycheck--line-cache))))
   1751     (when (= 0 (forward-line delta))
   1752       (setf (flycheck-line-cache-point flycheck--line-cache) (point))
   1753       (setf (flycheck-line-cache-line flycheck--line-cache) line))))
   1754 
   1755 (defun flycheck-line-column-to-position (line column)
   1756   "Return the point closest to LINE, COLUMN on line LINE.
   1757 
   1758 COLUMN is one-based."
   1759   (save-excursion
   1760     (flycheck-goto-line line)
   1761     (min (+ (point) (1- column)) (line-end-position))))
   1762 
   1763 (defun flycheck-line-column-at-point ()
   1764   "Return the line and column number at point."
   1765   (cons (line-number-at-pos) (1+ (- (point) (line-beginning-position)))))
   1766 
   1767 (defun flycheck-line-column-at-pos (pos)
   1768   "Return the line and column number at position POS.
   1769 
   1770 COLUMN is one-based."
   1771   (let ((inhibit-field-text-motion t))
   1772     (save-excursion
   1773       (goto-char pos)
   1774       (flycheck-line-column-at-point))))
   1775 
   1776 
   1777 ;;; Minibuffer tools
   1778 (defvar flycheck-read-checker-history nil
   1779   "`completing-read' history of `flycheck-read-checker'.")
   1780 
   1781 (defun flycheck-completing-read (prompt candidates default &optional history)
   1782   "Read a value from the minibuffer.
   1783 
   1784 Use `flycheck-completing-read-function' to read input from the
   1785 minibuffer with completion.
   1786 
   1787 Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT.
   1788 HISTORY is passed to `flycheck-completing-read-function'.
   1789 
   1790 Note that `flycheck-completing-read-function' may return an empty
   1791 string instead of nil, even when \"\" isn't among the candidates.
   1792 See `completing-read' for more details."
   1793   (funcall flycheck-completing-read-function
   1794            prompt candidates nil 'require-match nil history default))
   1795 
   1796 (defun flycheck-read-checker (prompt &optional default property candidates)
   1797   "Read a flycheck checker from minibuffer with PROMPT and DEFAULT.
   1798 
   1799 PROMPT is a string to show in the minibuffer as prompt.  It
   1800 should end with a single space.  DEFAULT is a symbol denoting the
   1801 default checker to use, if the user did not select any checker.
   1802 PROPERTY is a symbol denoting a syntax checker property.  If
   1803 non-nil, only complete syntax checkers which have a non-nil value
   1804 for PROPERTY.  CANDIDATES is an optional list of all syntax
   1805 checkers available for completion, defaulting to all defined
   1806 checkers.  If given, PROPERTY is ignored.
   1807 
   1808 Return the checker as symbol, or DEFAULT if no checker was
   1809 chosen.  If DEFAULT is nil and no checker was chosen, signal a
   1810 `user-error' if the underlying completion system does not provide
   1811 a default on its own."
   1812   (when (and default (not (flycheck-valid-checker-p default)))
   1813     (error "%S is no valid Flycheck checker" default))
   1814   (let* ((candidates (seq-map #'symbol-name
   1815                               (or candidates
   1816                                   (flycheck-defined-checkers property))))
   1817          (default (and default (symbol-name default)))
   1818          (input (flycheck-completing-read
   1819                  prompt candidates default
   1820                  'flycheck-read-checker-history)))
   1821     (when (string-empty-p input)
   1822       (unless default
   1823         (user-error "No syntax checker selected"))
   1824       (setq input default))
   1825     (let ((checker (intern input)))
   1826       (unless (flycheck-valid-checker-p checker)
   1827         (error "%S is not a valid Flycheck syntax checker" checker))
   1828       checker)))
   1829 
   1830 (defun flycheck-read-error-level (prompt)
   1831   "Read an error level from the user with PROMPT.
   1832 
   1833 Only offers level for which errors currently exist, in addition
   1834 to the default levels."
   1835   (let* ((levels (seq-map #'flycheck-error-level
   1836                           (flycheck-error-list-current-errors)))
   1837          (levels-with-defaults (append '(info warning error) levels))
   1838          (uniq-levels (seq-uniq levels-with-defaults))
   1839          (level (flycheck-completing-read prompt uniq-levels nil)))
   1840     (when (string-empty-p level) (setq level nil))
   1841     (and level (intern level))))
   1842 
   1843 
   1844 ;;; Checker API
   1845 (defun flycheck-defined-checkers (&optional property)
   1846   "Find all defined syntax checkers, optionally with PROPERTY.
   1847 
   1848 PROPERTY is a symbol.  If given, only return syntax checkers with
   1849 a non-nil value for PROPERTY.
   1850 
   1851 The returned list is sorted alphapetically by the symbol name of
   1852 the syntax checkers."
   1853   (let (defined-checkers)
   1854     (mapatoms (lambda (symbol)
   1855                 (when (and (flycheck-valid-checker-p symbol)
   1856                            (or (null property)
   1857                                (flycheck-checker-get symbol property)))
   1858                   (push symbol defined-checkers))))
   1859     (sort defined-checkers #'string<)))
   1860 
   1861 (defun flycheck-registered-checker-p (checker)
   1862   "Determine whether CHECKER is registered.
   1863 
   1864 A checker is registered if it is contained in
   1865 `flycheck-checkers'."
   1866   (and (flycheck-valid-checker-p checker)
   1867        (memq checker flycheck-checkers)))
   1868 
   1869 (defun flycheck-disabled-checker-p (checker)
   1870   "Determine whether CHECKER is disabled, manually or automatically."
   1871   (or (flycheck-manually-disabled-checker-p checker)
   1872       (flycheck-automatically-disabled-checker-p checker)))
   1873 
   1874 (defun flycheck-manually-disabled-checker-p (checker)
   1875   "Determine whether CHECKER has been manually disabled.
   1876 
   1877 A checker has been manually disabled if it is contained in
   1878 `flycheck-disabled-checkers'."
   1879   (memq checker flycheck-disabled-checkers))
   1880 
   1881 (defun flycheck-automatically-disabled-checker-p (checker)
   1882   "Determine whether CHECKER has been automatically disabled.
   1883 
   1884 A checker has been automatically disabled if it is contained in
   1885 `flycheck--automatically-disabled-checkers'."
   1886   (memq checker flycheck--automatically-disabled-checkers))
   1887 
   1888 
   1889 ;;; Generic syntax checkers
   1890 (defconst flycheck-generic-checker-version 2
   1891   "The internal version of generic syntax checker declarations.
   1892 
   1893 Flycheck will not use syntax checkers whose generic version is
   1894 less than this constant.")
   1895 
   1896 (defsubst flycheck--checker-property-name (property)
   1897   "Return the SYMBOL property for checker PROPERTY."
   1898   (intern (concat "flycheck-" (symbol-name property))))
   1899 
   1900 (defun flycheck-checker-get (checker property)
   1901   "Get the value of CHECKER's PROPERTY."
   1902   (get checker (flycheck--checker-property-name property)))
   1903 
   1904 (gv-define-setter flycheck-checker-get (value checker property)
   1905   `(setf (get ,checker (flycheck--checker-property-name ,property)) ,value))
   1906 
   1907 (defun flycheck-validate-next-checker (next &optional strict)
   1908   "Validate NEXT checker.
   1909 
   1910 With STRICT non-nil, also check whether the syntax checker and
   1911 the error level in NEXT are valid.  Otherwise just check whether
   1912 these are symbols.
   1913 
   1914 Signal an error if NEXT is not a valid entry for
   1915 `:next-checkers'."
   1916   (when (symbolp next)
   1917     (setq next (cons t next)))
   1918   (pcase next
   1919     (`(,level . ,checker)
   1920      (if strict
   1921          (progn
   1922            (unless (or (eq level t) (flycheck-error-level-p level))
   1923              (error "%S is not a valid Flycheck error level" level))
   1924            (unless (flycheck-valid-checker-p checker)
   1925              (error "%s is not a valid Flycheck syntax checker" checker)))
   1926        (unless (symbolp level)
   1927          (error "Error level %S must be a symbol" level))
   1928        (unless (symbolp checker)
   1929          (error "Checker %S must be a symbol" checker))))
   1930     (_ (error "%S must be a symbol or cons cell" next)))
   1931   t)
   1932 
   1933 (defun flycheck-define-generic-checker (symbol docstring &rest properties)
   1934   "Define SYMBOL as generic syntax checker.
   1935 
   1936 Any syntax checker defined with this macro is eligible for manual
   1937 syntax checker selection with `flycheck-select-checker'.  To make
   1938 the new syntax checker available for automatic selection, it must
   1939 be registered in `flycheck-checkers'.
   1940 
   1941 DOCSTRING is the documentation of the syntax checker, for
   1942 `flycheck-describe-checker'.  The following PROPERTIES constitute
   1943 a generic syntax checker.  Unless otherwise noted, all properties
   1944 are mandatory.
   1945 
   1946 `:start FUNCTION'
   1947      A function to start the syntax checker.
   1948 
   1949      FUNCTION shall take two arguments and return a context
   1950      object if the checker is started successfully.  Otherwise it
   1951      shall signal an error.
   1952 
   1953      The first argument is the syntax checker being started.  The
   1954      second is a callback function to report state changes to
   1955      Flycheck.  The callback takes two arguments STATUS DATA,
   1956      where STATUS is a symbol denoting the syntax checker status
   1957      and DATA an optional argument with additional data for the
   1958      status report.  See `flycheck-report-buffer-checker-status'
   1959      for more information about STATUS and DATA.
   1960 
   1961      FUNCTION may be synchronous or asynchronous, i.e. it may
   1962      call the given callback either immediately, or at some later
   1963      point (e.g. from a process sentinel).
   1964 
   1965      A syntax checker _must_ call CALLBACK at least once with a
   1966      STATUS that finishes the current syntax checker.  Otherwise
   1967      Flycheck gets stuck at the current syntax check with this
   1968      syntax checker.
   1969 
   1970      The context object returned by FUNCTION is passed to
   1971      `:interrupt'.
   1972 
   1973 `:interrupt FUNCTION'
   1974      A function to interrupt the syntax check.
   1975 
   1976      FUNCTION is called with the syntax checker and the context
   1977      object returned by the `:start' function and shall try to
   1978      interrupt the syntax check.  The context may be nil, if the
   1979      syntax check is interrupted before actually started.
   1980      FUNCTION should handle this situation.
   1981 
   1982      If it cannot interrupt the syntax check, it may either
   1983      signal an error or silently ignore the attempt to interrupt
   1984      the syntax checker, depending on the severity of the
   1985      situation.
   1986 
   1987      If interrupting the syntax check failed, Flycheck will let
   1988      the syntax check continue, but ignore any status reports.
   1989      Notably, it won't highlight any errors reported by the
   1990      syntax check in the buffer.
   1991 
   1992      This property is optional.  If omitted, Flycheck won't
   1993      attempt to interrupt syntax checks with this syntax checker,
   1994      and simply ignore their results.
   1995 
   1996 `:print-doc FUNCTION'
   1997      A function to print additional documentation into the Help
   1998      buffer of this checker.
   1999 
   2000      FUNCTION is called when creating the Help buffer for the
   2001      syntax checker, with the syntax checker as single argument,
   2002      after printing the name of the syntax checker and its modes
   2003      and predicate, but before printing DOCSTRING.  It may insert
   2004      additional documentation into the current buffer.
   2005 
   2006      The call occurs within `with-help-window'.  Hence
   2007      `standard-output' points to the current buffer, so you may
   2008      use `princ' and friends to add content.  Also, the current
   2009      buffer is put into Help mode afterwards, which automatically
   2010      turns symbols into references, if possible.
   2011 
   2012      This property is optional.  If omitted, no additional
   2013      documentation is printed for this syntax checker.
   2014 
   2015 :verify FUNCTION
   2016      A function to verify the checker for the current buffer.
   2017 
   2018      FUNCTION is called with the syntax checker as single
   2019      argument, and shall return a list of
   2020      `flycheck-verification-result' objects indicating whether
   2021      the syntax checker could be used in the current buffer, and
   2022      highlighting potential setup problems.
   2023 
   2024      This property is optional.  If omitted, no additional
   2025      verification occurs for this syntax checker.  It is however
   2026      absolutely recommended that you add a `:verify' function to
   2027      your syntax checker, because it will help users to spot
   2028      potential setup problems.
   2029 
   2030 `:modes MODES'
   2031      A major mode symbol or a list thereof, denoting major modes
   2032      to use this syntax checker in.
   2033 
   2034      This syntax checker will only be used in buffers whose
   2035      `major-mode' is contained in MODES.
   2036 
   2037      If `:predicate' is also given the syntax checker will only
   2038      be used in buffers for which the `:predicate' returns
   2039      non-nil.
   2040 
   2041 `:predicate FUNCTION'
   2042      A function to determine whether to use the syntax checker in
   2043      the current buffer.
   2044 
   2045      FUNCTION is called without arguments and shall return
   2046      non-nil if this syntax checker shall be used to check the
   2047      current buffer.  Otherwise it shall return nil.
   2048 
   2049      If this checker has a `:working-directory' FUNCTION is
   2050      called with `default-directory' bound to the checker's
   2051      working directory.
   2052 
   2053      FUNCTION is only called in matching major modes.
   2054 
   2055      This property is optional.
   2056 
   2057 `:enabled FUNCTION'
   2058      A function to determine whether to use the syntax checker in
   2059      the current buffer.
   2060 
   2061      This property behaves as `:predicate', except that it's only
   2062      called the first time a syntax checker is to be used in a buffer.
   2063 
   2064      FUNCTION is called without arguments and shall return
   2065      non-nil if this syntax checker shall be used to check the
   2066      current buffer.  Otherwise it shall return nil.
   2067 
   2068      If FUNCTION returns a non-nil value the checker is put in a
   2069      whitelist in `flycheck--automatically-enabled-checkers' to
   2070      prevent further invocations of `:enabled'.  Otherwise it is
   2071      disabled via `flycheck--automatically-disabled-checkers' to
   2072      prevent any further use of it.
   2073 
   2074      If this checker has a `:working-directory' FUNCTION is
   2075      called with `default-directory' bound to the checker's
   2076      working directory.
   2077 
   2078      FUNCTION is only called in matching major modes.
   2079 
   2080      This property is optional.
   2081 
   2082 `:error-filter FUNCTION'
   2083      A function to filter the errors returned by this checker.
   2084 
   2085      FUNCTION is called with the list of `flycheck-error' objects
   2086      returned by the syntax checker and shall return another list
   2087      of `flycheck-error' objects, which is considered the final
   2088      result of this syntax checker.
   2089 
   2090      FUNCTION is free to add, remove or modify errors, whether in
   2091      place or by copying.
   2092 
   2093      This property is optional.  The default filter is
   2094      `identity'.
   2095 
   2096 `:error-explainer FUNCTION'
   2097      A function to return an explanation text for errors
   2098      generated by this checker.
   2099 
   2100      FUNCTION is called with a `flycheck-error' object, in the
   2101      buffer of that error.  It shall return an explanation
   2102      message for the error.
   2103 
   2104      The message can take any of the following forms:
   2105      - A string, which will be displayed to the user
   2106      - A function (likely a closure), which will be called with
   2107        `standard-output' set to a `flycheck-explain-error-mode'
   2108        buffer, and should write to it.
   2109      - A cons `(url . ,URL), indicating that the explanation can
   2110        be found online at URL.
   2111      - nil if there is no explanation for this error.
   2112 
   2113      If URL is provided by the checker, and cannot be composed
   2114      from other elements in the `flycheck-error' object, consider
   2115      passing the URL via text properties:
   2116 
   2117        ;; During the error object creation
   2118        (put-text-property 0 1 \\='explainer-url .url .check_id)
   2119 
   2120        ;; In the error-explainer FUNCTION
   2121        (let ((id (flycheck-error-id err)))
   2122          (and id `(url . ,(get-text-property 0 \\='explainer-url id))))
   2123 
   2124      This property is optional.
   2125 
   2126 `:next-checkers NEXT-CHECKERS'
   2127      A list denoting syntax checkers to apply after this syntax
   2128      checker, in what we call \"chaining\" of syntax checkers.
   2129 
   2130      Each ITEM is a cons cell `(LEVEL . CHECKER)'.  CHECKER is a
   2131      syntax checker to run after this syntax checker.  LEVEL is
   2132      an error level.  CHECKER will only be used if there are no
   2133      current errors of at least LEVEL.  LEVEL may also be t, in
   2134      which case CHECKER is used regardless of the current errors.
   2135 
   2136      ITEM may also be a syntax checker symbol, which is
   2137      equivalent to `(t . ITEM)'.
   2138 
   2139      Flycheck tries all items in order of declaration, and uses
   2140      the first whose LEVEL matches and whose CHECKER is
   2141      registered and can be used for the current buffer.
   2142 
   2143      This feature is typically used to apply more than one syntax
   2144      checker to a buffer.  For instance, you might first use a
   2145      compiler to check a buffer for syntax and type errors, and
   2146      then run a linting tool that checks for insecure code, or
   2147      questionable style.
   2148 
   2149      This property is optional.  If omitted, it defaults to the
   2150      nil, i.e. no other syntax checkers are applied after this
   2151      syntax checker.
   2152 
   2153 `:working-directory FUNCTION'
   2154      The value of `default-directory' when invoking `:start'.
   2155 
   2156      FUNCTION is a function taking the syntax checker as sole
   2157      argument.  It shall return the absolute path to an existing
   2158      directory to use as `default-directory' for `:start' or
   2159      nil to fall back to the `default-directory' of the current
   2160      buffer.
   2161 
   2162      This property is optional.  If omitted, invoke `:start'
   2163      from the `default-directory' of the buffer being checked.
   2164 
   2165 Signal an error, if any property has an invalid value."
   2166   (declare (indent 1)
   2167            (doc-string 2))
   2168   (let ((start (plist-get properties :start))
   2169         (interrupt (plist-get properties :interrupt))
   2170         (print-doc (plist-get properties :print-doc))
   2171         (modes (plist-get properties :modes))
   2172         (predicate (plist-get properties :predicate))
   2173         (verify (plist-get properties :verify))
   2174         (enabled (plist-get properties :enabled))
   2175         (filter (or (plist-get properties :error-filter) #'identity))
   2176         (explainer (plist-get properties :error-explainer))
   2177         (next-checkers (plist-get properties :next-checkers))
   2178         (file (flycheck-current-load-file))
   2179         (working-directory (plist-get properties :working-directory)))
   2180 
   2181     (unless (listp modes)
   2182       (setq modes (list modes)))
   2183 
   2184     (unless (functionp start)
   2185       (error ":start %S of syntax checker %s is not a function" start symbol))
   2186     (unless (or (null interrupt) (functionp interrupt))
   2187       (error ":interrupt %S of syntax checker %s is not a function"
   2188              interrupt symbol))
   2189     (unless (or (null print-doc) (functionp print-doc))
   2190       (error ":print-doc %S of syntax checker %s is not a function"
   2191              print-doc symbol))
   2192     (unless (or (null verify) (functionp verify))
   2193       (error ":verify %S of syntax checker %S is not a function"
   2194              verify symbol))
   2195     (unless (or (null enabled) (functionp enabled))
   2196       (error ":enabled %S of syntax checker %S is not a function"
   2197              enabled symbol))
   2198     (unless modes
   2199       (error "Missing :modes in syntax checker %s" symbol))
   2200     (dolist (mode modes)
   2201       (unless (symbolp mode)
   2202         (error "Invalid :modes %s in syntax checker %s, %s must be a symbol"
   2203                modes symbol mode)))
   2204     (unless (or (null predicate) (functionp predicate))
   2205       (error ":predicate %S of syntax checker %s  is not a function"
   2206              predicate symbol))
   2207     (unless (functionp filter)
   2208       (error ":error-filter %S of syntax checker %s is not a function"
   2209              filter symbol))
   2210     (unless (or (null explainer) (functionp explainer))
   2211       (error ":error-explainer %S of syntax checker %S is not a function"
   2212              explainer symbol))
   2213     (dolist (checker next-checkers)
   2214       (flycheck-validate-next-checker checker))
   2215 
   2216     (let ((real-predicate
   2217            (and predicate
   2218                 (lambda ()
   2219                   ;; Run predicate in the checker's default directory
   2220                   (let ((default-directory
   2221                           (flycheck-compute-working-directory symbol)))
   2222                     (funcall predicate)))))
   2223           (real-enabled
   2224            (lambda ()
   2225              (if (flycheck-valid-checker-p symbol)
   2226                  (or (null enabled)
   2227                      ;; Run enabled in the checker's default directory
   2228                      (let ((default-directory
   2229                              (flycheck-compute-working-directory symbol)))
   2230                        (funcall enabled)))
   2231                (lwarn 'flycheck
   2232                       :warning "%S is no valid Flycheck syntax checker.
   2233 Try to reinstall the package defining this syntax checker." symbol)
   2234                nil))))
   2235       (pcase-dolist (`(,prop . ,value)
   2236                      `((start             . ,start)
   2237                        (interrupt         . ,interrupt)
   2238                        (print-doc         . ,print-doc)
   2239                        (modes             . ,modes)
   2240                        (predicate         . ,real-predicate)
   2241                        (verify            . ,verify)
   2242                        (enabled           . ,real-enabled)
   2243                        (error-filter      . ,filter)
   2244                        (error-explainer   . ,explainer)
   2245                        (next-checkers     . ,next-checkers)
   2246                        (documentation     . ,docstring)
   2247                        (file              . ,file)
   2248                        (working-directory . ,working-directory)))
   2249         (setf (flycheck-checker-get symbol prop) value)))
   2250 
   2251     ;; Track the version, to avoid breakage if the internal format changes
   2252     (setf (flycheck-checker-get symbol 'generic-checker-version)
   2253           flycheck-generic-checker-version)))
   2254 
   2255 (defun flycheck-valid-checker-p (checker)
   2256   "Check whether a CHECKER is valid.
   2257 
   2258 A valid checker is a symbol defined as syntax checker with
   2259 `flycheck-define-checker'."
   2260   (and (symbolp checker)
   2261        (= (or (get checker 'flycheck-generic-checker-version) 0)
   2262           flycheck-generic-checker-version)))
   2263 
   2264 (defun flycheck-checker-supports-major-mode-p (checker &optional mode)
   2265   "Whether CHECKER supports the given major MODE.
   2266 
   2267 CHECKER is a syntax checker symbol and MODE a major mode symbol.
   2268 Look at the `modes' property of CHECKER to determine whether
   2269 CHECKER supports buffers in the given major MODE.
   2270 
   2271 MODE defaults to the value of `major-mode' if omitted or nil.
   2272 
   2273 Return non-nil if CHECKER supports MODE and nil otherwise."
   2274   (let ((mode (or mode major-mode)))
   2275     (memq mode (flycheck-checker-get checker 'modes))))
   2276 
   2277 (define-obsolete-variable-alias 'flycheck-enabled-checkers
   2278   'flycheck--automatically-enabled-checkers "32")
   2279 
   2280 (defvar flycheck--automatically-enabled-checkers nil
   2281   "Syntax checkers included in automatic selection.
   2282 
   2283 A list of Flycheck syntax checkers included in automatic
   2284 selection for the current buffer.")
   2285 (make-variable-buffer-local 'flycheck--automatically-enabled-checkers)
   2286 
   2287 (defun flycheck-may-enable-checker (checker)
   2288   "Whether a generic CHECKER may be enabled for current buffer.
   2289 
   2290 Return non-nil if CHECKER may be used for the current buffer, and
   2291 nil otherwise.  The result of the `:enabled' check, if any, is
   2292 cached."
   2293   (and
   2294    ;; May only enable valid checkers
   2295    (flycheck-valid-checker-p checker)
   2296    ;; Don't run the :enabled check if the checker is already disabled…
   2297    (not (flycheck-disabled-checker-p checker))
   2298    (or
   2299     ;; …or if we've already cached the result
   2300     (memq checker flycheck--automatically-enabled-checkers)
   2301     (let* ((enabled (flycheck-checker-get checker 'enabled))
   2302            (may-enable (or (null enabled) (funcall enabled))))
   2303       ;; Cache the result
   2304       (if may-enable
   2305           (cl-pushnew checker flycheck--automatically-enabled-checkers)
   2306         (cl-pushnew checker flycheck--automatically-disabled-checkers))
   2307       may-enable))))
   2308 
   2309 (defun flycheck-reset-enabled-checker (checker)
   2310   "Reset the `:enabled' test of CHECKER.
   2311 
   2312 Forget that CHECKER has been enabled or automatically disabled
   2313 from a previous `:enabled' test.  The result of the `:enabled'
   2314 test is cached in `flycheck-may-enable-checker': if you wish to
   2315 test the `:enabled' predicate again, you must first reset its
   2316 state using this function."
   2317   (when (memq checker flycheck--automatically-disabled-checkers)
   2318     (setq flycheck--automatically-disabled-checkers
   2319           (remq checker flycheck--automatically-disabled-checkers)))
   2320   (when (memq checker flycheck--automatically-enabled-checkers)
   2321     (setq flycheck--automatically-enabled-checkers
   2322           (remq checker flycheck--automatically-enabled-checkers)))
   2323   (flycheck-buffer))
   2324 
   2325 (defun flycheck-may-use-checker (checker)
   2326   "Whether a generic CHECKER may be used.
   2327 
   2328 Return non-nil if CHECKER may be used for the current buffer, and
   2329 nil otherwise."
   2330   (let ((predicate (flycheck-checker-get checker 'predicate)))
   2331     (and (flycheck-valid-checker-p checker)
   2332          (flycheck-checker-supports-major-mode-p checker)
   2333          (flycheck-may-enable-checker checker)
   2334          (or (null predicate) (funcall predicate)))))
   2335 
   2336 (defun flycheck-may-use-next-checker (next-checker)
   2337   "Determine whether NEXT-CHECKER may be used."
   2338   (when (symbolp next-checker)
   2339     (push t next-checker))
   2340   (let ((level (car next-checker))
   2341         (next-checker (cdr next-checker)))
   2342     (and (or (eq level t)
   2343              (flycheck-has-max-current-errors-p level))
   2344          (flycheck-registered-checker-p next-checker)
   2345          (flycheck-may-use-checker next-checker))))
   2346 
   2347 
   2348 ;;; Help for generic syntax checkers
   2349 (define-button-type 'help-flycheck-checker-def
   2350   :supertype 'help-xref
   2351   'help-function #'flycheck-goto-checker-definition
   2352   'help-echo "mouse-1, RET: find Flycheck checker definition")
   2353 
   2354 (defconst flycheck-find-checker-regexp
   2355   (rx line-start (zero-or-more (syntax whitespace))
   2356       "(" symbol-start
   2357       (or "flycheck-define-checker" "flycheck-define-command-checker")
   2358       symbol-end
   2359       (eval (list 'regexp find-function-space-re))
   2360       (? "'")
   2361       symbol-start "%s" symbol-end
   2362       (or (syntax whitespace) line-end))
   2363   "Regular expression to find a checker definition.")
   2364 
   2365 (add-to-list 'find-function-regexp-alist
   2366              '(flycheck-checker . flycheck-find-checker-regexp))
   2367 
   2368 (defun flycheck-goto-checker-definition (checker file)
   2369   "Go to to the definition of CHECKER in FILE."
   2370   (let ((location (find-function-search-for-symbol
   2371                    checker 'flycheck-checker file)))
   2372     (pop-to-buffer (car location))
   2373     (if (cdr location)
   2374         (goto-char (cdr location))
   2375       (message "Unable to find checker location in file"))))
   2376 
   2377 (defun flycheck-checker-at-point ()
   2378   "Return the Flycheck checker found at or before point.
   2379 
   2380 Return nil if there is no checker."
   2381   (let ((symbol (variable-at-point 'any-symbol)))
   2382     (when (flycheck-valid-checker-p symbol)
   2383       symbol)))
   2384 
   2385 (defun flycheck-describe-checker (checker)
   2386   "Display the documentation of CHECKER.
   2387 
   2388 CHECKER is a checker symbol.
   2389 
   2390 Pop up a help buffer with the documentation of CHECKER."
   2391   (interactive
   2392    (let* ((enable-recursive-minibuffers t)
   2393           (default (or (flycheck-checker-at-point)
   2394                        (ignore-errors (flycheck-get-checker-for-buffer))))
   2395           (prompt (if default
   2396                       (format "Describe syntax checker (default %s): " default)
   2397                     "Describe syntax checker: ")))
   2398      (list (flycheck-read-checker prompt default))))
   2399   (unless (flycheck-valid-checker-p checker)
   2400     (user-error "You didn't specify a Flycheck syntax checker"))
   2401   (let ((filename (flycheck-checker-get checker 'file))
   2402         (modes (flycheck-checker-get checker 'modes))
   2403         (predicate (flycheck-checker-get checker 'predicate))
   2404         (print-doc (flycheck-checker-get checker 'print-doc))
   2405         (next-checkers (flycheck-checker-get checker 'next-checkers))
   2406         (help-xref-following
   2407          ;; Ensure that we don't reuse buffers like `flycheck-verify-checker',
   2408          ;; and that we don't error out if a `help-flycheck-checker-doc' button
   2409          ;; is added outside of a documentation window.
   2410          (and help-xref-following (eq major-mode 'help-mode))))
   2411     (help-setup-xref (list #'flycheck-describe-checker checker)
   2412                      (called-interactively-p 'interactive))
   2413     (save-excursion
   2414       (with-help-window (help-buffer)
   2415         (princ (format "%s is a Flycheck syntax checker" checker))
   2416         (when filename
   2417           (princ (format " in `%s'" (file-name-nondirectory filename)))
   2418           (with-current-buffer standard-output
   2419             (save-excursion
   2420               (re-search-backward "`\\([^`']+\\)'" nil t)
   2421               (help-xref-button 1 'help-flycheck-checker-def
   2422                                 checker filename))))
   2423         (princ ".\n\n")
   2424 
   2425         (let ((modes-start (with-current-buffer standard-output (point-max))))
   2426           ;; Track the start of the modes documentation, to properly re-fill
   2427           ;; it later
   2428           (princ "  This syntax checker checks syntax in the major mode(s) ")
   2429           (princ (string-join
   2430                   (seq-map (apply-partially #'format "`%s'") modes)
   2431                   ", "))
   2432           (when predicate
   2433             (princ ", and uses a custom predicate"))
   2434           (princ ".")
   2435           (when next-checkers
   2436             (princ "  It runs the following checkers afterwards:"))
   2437           (with-current-buffer standard-output
   2438             (save-excursion
   2439               (fill-region-as-paragraph modes-start (point-max))))
   2440           (princ "\n")
   2441 
   2442           ;; Print the list of next checkers
   2443           (when next-checkers
   2444             (princ "\n")
   2445             (let ((beg-checker-list (with-current-buffer standard-output
   2446                                       (point))))
   2447               (dolist (next-checker next-checkers)
   2448                 (if (symbolp next-checker)
   2449                     (princ (format "     * `%s'\n" next-checker))
   2450                   (princ (format "     * `%s' (maximum level `%s')\n"
   2451                                  (cdr next-checker) (car next-checker)))))
   2452               ;;
   2453               (with-current-buffer standard-output
   2454                 (save-excursion
   2455                   (while (re-search-backward "`\\([^`']+\\)'"
   2456                                              beg-checker-list t)
   2457                     (let ((checker (intern-soft (match-string 1))))
   2458                       (when (flycheck-valid-checker-p checker)
   2459                         (help-xref-button 1 'help-flycheck-checker-doc
   2460                                           checker)))))))))
   2461         ;; Call the custom print-doc function of the checker, if present
   2462         (when print-doc
   2463           (funcall print-doc checker))
   2464         ;; Ultimately, print the docstring
   2465         (princ "\nDocumentation:\n")
   2466         (princ (flycheck-checker-get checker 'documentation))))))
   2467 
   2468 
   2469 ;;; Syntax checker verification
   2470 (cl-defstruct (flycheck-verification-result
   2471                (:constructor flycheck-verification-result-new))
   2472   "Structure for storing a single verification result.
   2473 
   2474 Slots:
   2475 
   2476 `label'
   2477      A label for this result, as string
   2478 
   2479 `message'
   2480      A message for this result, as string
   2481 
   2482 `face'
   2483      The face to use for the `message'.
   2484 
   2485      You can either use a face symbol, or a list of face symbols."
   2486   label message face)
   2487 
   2488 (defun flycheck-verify-generic-checker (checker)
   2489   "Verify a generic CHECKER in the current buffer.
   2490 
   2491 Return a list of `flycheck-verification-result' objects."
   2492   (let (results
   2493         (predicate (flycheck-checker-get checker 'predicate))
   2494         (enabled (flycheck-checker-get checker 'enabled))
   2495         (verify (flycheck-checker-get checker 'verify)))
   2496     (when enabled
   2497       (let ((result (funcall enabled)))
   2498         (push (flycheck-verification-result-new
   2499                :label (propertize "may enable" 'help-echo ":enable")
   2500                :message (if result "yes" "no")
   2501                :face (if result 'success '(bold warning)))
   2502               results)))
   2503     (when predicate
   2504       (let ((result (funcall predicate)))
   2505         (push (flycheck-verification-result-new
   2506                :label (propertize "may run" 'help-echo ":predicate")
   2507                :message (prin1-to-string (not (null result)))
   2508                :face (if result 'success '(bold warning)))
   2509               results)))
   2510     (append (nreverse results)
   2511             (and verify (funcall verify checker)))))
   2512 
   2513 (define-button-type 'help-flycheck-checker-doc
   2514   :supertype 'help-xref
   2515   'help-function #'flycheck-describe-checker
   2516   'help-echo "mouse-1, RET: describe Flycheck checker")
   2517 
   2518 (define-button-type 'flycheck-button
   2519   'follow-link t
   2520   'action (lambda (pos)
   2521             (apply (get-text-property pos 'flycheck-action)
   2522                    (get-text-property pos 'flycheck-data))
   2523             ;; Revert the verify-setup buffer since it is now stale
   2524             (revert-buffer))
   2525   'face 'flycheck-verify-select-checker)
   2526 
   2527 (define-button-type 'flycheck-checker-select
   2528   :supertype 'flycheck-button
   2529   'flycheck-action (lambda (buffer checker)
   2530                      (with-current-buffer buffer
   2531                        (flycheck-select-checker checker)))
   2532   'help-echo "mouse-1, RET: select this checker")
   2533 
   2534 (define-button-type 'flycheck-checker-enable
   2535   :supertype 'flycheck-button
   2536   'flycheck-action (lambda (buffer checker)
   2537                      (interactive)
   2538                      (with-current-buffer buffer
   2539                        (flycheck--toggle-checker checker t)
   2540                        (flycheck-buffer)))
   2541   'help-echo "mouse-1, RET: re-enable this checker in this buffer")
   2542 
   2543 (define-button-type 'flycheck-checker-reset-enabled
   2544   :supertype 'flycheck-button
   2545   'flycheck-action (lambda (buffer checker)
   2546                      (with-current-buffer buffer
   2547                        (flycheck-reset-enabled-checker checker)))
   2548   'help-echo "mouse-1, RET: try to re-enable this checker")
   2549 
   2550 (defun flycheck--verify-princ-checker (checker buffer
   2551                                                &optional with-mm with-select)
   2552   "Print verification result of CHECKER for BUFFER.
   2553 
   2554 When WITH-MM is given and non-nil, also include the major mode
   2555 into the verification results.
   2556 
   2557 When WITH-SELECT is non-nil, add a button to select this checker."
   2558   (princ "  ")
   2559   (insert-button (symbol-name checker)
   2560                  'type 'help-flycheck-checker-doc
   2561                  'help-args (list checker))
   2562   (cond
   2563    ((with-current-buffer buffer
   2564       (flycheck-manually-disabled-checker-p checker))
   2565     (insert (propertize " (manually disabled) " 'face '(bold error)))
   2566     (insert-text-button "enable"
   2567                         'type 'flycheck-checker-enable
   2568                         'flycheck-data (list buffer checker)))
   2569    ((with-current-buffer buffer
   2570       (flycheck-automatically-disabled-checker-p checker))
   2571     (insert (propertize " (automatically disabled) " 'face '(bold error)))
   2572     (insert-text-button "reset"
   2573                         'type 'flycheck-checker-reset-enabled
   2574                         'flycheck-data (list buffer checker))))
   2575   (when (eq checker (buffer-local-value 'flycheck-checker buffer))
   2576     (insert (propertize " (explicitly selected)" 'face 'bold)))
   2577   (when with-select
   2578     (princ "  ")
   2579     (insert-text-button "select"
   2580                         'type 'flycheck-checker-select
   2581                         'flycheck-data (list buffer checker)))
   2582   (princ "\n")
   2583   (let ((results (with-current-buffer buffer
   2584                    (append (flycheck-verify-generic-checker checker)
   2585                            (flycheck--verify-next-checkers checker)))))
   2586     (when with-mm
   2587       (with-current-buffer buffer
   2588         (let ((message-and-face
   2589                (if (flycheck-checker-supports-major-mode-p checker)
   2590                    (cons (format "`%s' supported" major-mode) 'success)
   2591                  (cons (format "`%s' not supported" major-mode) 'error))))
   2592           (push (flycheck-verification-result-new
   2593                  :label "major mode"
   2594                  :message (car message-and-face)
   2595                  :face (cdr message-and-face))
   2596                 results))))
   2597     (let* ((label-length
   2598             (seq-max (mapcar
   2599                       (lambda (res)
   2600                         (length (flycheck-verification-result-label res)))
   2601                       results)))
   2602            (message-column (+ 8 label-length)))
   2603       (dolist (result results)
   2604         (princ "    - ")
   2605         (princ (flycheck-verification-result-label result))
   2606         (princ ": ")
   2607         (princ (make-string (- message-column (current-column)) ?\ ))
   2608         (let ((message (flycheck-verification-result-message result))
   2609               (face (flycheck-verification-result-face result)))
   2610           ;; If face is nil, using propertize erases the face already contained
   2611           ;; by the message.  We don't want that, since this would remove the
   2612           ;; button face from the checker chain result.
   2613           (insert (if face (propertize message 'face face) message)))
   2614         (princ "\n"))))
   2615   (princ "\n"))
   2616 
   2617 (defun flycheck--get-next-checker-symbol (next)
   2618   "Get the checker symmbol of NEXT checker.
   2619 
   2620 NEXT should be either a cons (NEXT-CHECKER . LEVEL) or a
   2621 symbol."
   2622   (if (consp next) (cdr next) next))
   2623 
   2624 (defun flycheck-get-next-checkers (checker)
   2625   "Return the immediate next checkers of CHECKER.
   2626 
   2627 This is a list of checker symbols.  The error levels of the
   2628 `:next-checker' property are ignored."
   2629   (mapcar #'flycheck--get-next-checker-symbol
   2630           (flycheck-checker-get checker 'next-checkers)))
   2631 
   2632 (defun flycheck-all-next-checkers (checker)
   2633   "Return all checkers that may follow CHECKER.
   2634 
   2635 Return the transitive closure of the next-checker relation.  The
   2636 return value is a list of checkers, not including CHECKER."
   2637   (let ((next-checkers)
   2638         (visited)
   2639         (queue (list checker)))
   2640     (while queue
   2641       (let ((c (pop queue)))
   2642         (push c visited)
   2643         (dolist (n (flycheck-get-next-checkers c))
   2644           (push n next-checkers)
   2645           (unless (memq n visited)
   2646             (cl-pushnew n queue)))))
   2647     (seq-uniq next-checkers)))
   2648 
   2649 (defun flycheck--verify-next-checkers (checker)
   2650   "Return a verification result for the next checkers of CHECKER."
   2651   (when-let (next (flycheck-get-next-checkers checker))
   2652     (list
   2653      (flycheck-verification-result-new
   2654       :label "next checkers"
   2655       ;; We use `make-text-button' to preserve the button properties in the
   2656       ;; string
   2657       :message (mapconcat
   2658                 (lambda (checker)
   2659                   (make-text-button (symbol-name checker) nil
   2660                                     'type 'help-flycheck-checker-doc
   2661                                     'help-args (list checker)))
   2662                 next
   2663                 ", ")))))
   2664 
   2665 (defun flycheck--verify-print-header (desc buffer)
   2666   "Print a title with DESC for BUFFER in the current buffer.
   2667 
   2668 DESC is an arbitrary string containing a description, and BUFFER
   2669 is the buffer being verified.  The name and the major mode mode
   2670 of BUFFER are printed.
   2671 
   2672 DESC and information about BUFFER are printed in the current
   2673 buffer."
   2674   (princ desc)
   2675   (insert (propertize (buffer-name buffer) 'face 'bold))
   2676   (princ " in ")
   2677   (let ((mode (buffer-local-value 'major-mode buffer)))
   2678     (insert-button (symbol-name mode)
   2679                    'type 'help-function
   2680                    'help-args (list mode)))
   2681   (princ ":\n\n"))
   2682 
   2683 (defun flycheck--verify-print-footer (buffer)
   2684   "Print a footer for BUFFER in the current buffer.
   2685 
   2686 BUFFER is the buffer being verified."
   2687   (princ "Flycheck Mode is ")
   2688   (let ((enabled (buffer-local-value 'flycheck-mode buffer)))
   2689     (insert (propertize (if enabled "enabled" "disabled")
   2690                         'face (if enabled 'success '(warning bold)))))
   2691   (princ
   2692    (with-current-buffer buffer
   2693      ;; Use key binding state in the verified buffer to print the help.
   2694      (substitute-command-keys
   2695       ".  Use \\[universal-argument] \\[flycheck-disable-checker] \
   2696 to enable disabled checkers.")))
   2697   (save-excursion
   2698     (let ((end (point)))
   2699       (backward-paragraph)
   2700       (fill-region-as-paragraph (point) end)))
   2701 
   2702   (princ "\n\n--------------------\n\n")
   2703   (princ (format "Flycheck version: %s\n" (flycheck--pkg-version)))
   2704   (princ (format "Emacs version:    %s\n" emacs-version))
   2705   (princ (format "System:           %s\n" system-configuration))
   2706   (princ (format "Window system:    %S\n" window-system)))
   2707 
   2708 (define-derived-mode flycheck-verify-mode help-mode
   2709   "Flycheck verification"
   2710   "Major mode to display Flycheck verification results."
   2711   ;; `help-mode-finish' will restore `buffer-read-only'
   2712   (setq buffer-read-only nil))
   2713 
   2714 (defun flycheck-verify-checker (checker)
   2715   "Check whether a CHECKER can be used in this buffer.
   2716 
   2717 Show a buffer listing possible problems that prevent CHECKER from
   2718 being used for the current buffer.
   2719 
   2720 Note: Do not use this function to check whether a syntax checker
   2721 is applicable from Emacs Lisp code.  Use
   2722 `flycheck-may-use-checker' instead."
   2723   (interactive (list (flycheck-read-checker "Checker to verify: ")))
   2724   (unless (flycheck-valid-checker-p checker)
   2725     (user-error "%s is not a syntax checker" checker))
   2726 
   2727   ;; Save the buffer to make sure that all predicates are good
   2728   ;; FIXME: this may be surprising to users, with unintended side-effects.
   2729   (when (and (buffer-file-name) (buffer-modified-p))
   2730     (save-buffer))
   2731 
   2732   (let ((buffer (current-buffer)))
   2733     (with-help-window "*Flycheck checker*"
   2734       (with-current-buffer standard-output
   2735         (flycheck-verify-mode)
   2736         (flycheck--verify-print-header "Syntax checker in buffer " buffer)
   2737         (flycheck--verify-princ-checker checker buffer 'with-mm)
   2738         (if (with-current-buffer buffer (flycheck-may-use-checker checker))
   2739             (insert (propertize
   2740                      "Flycheck can use this syntax checker for this buffer.\n"
   2741                      'face 'success))
   2742           (insert (propertize
   2743                    "Flycheck cannot use this syntax checker for this buffer.\n"
   2744                    'face 'error)))
   2745         (insert "\n")
   2746         (flycheck--verify-print-footer buffer)))))
   2747 
   2748 (defun flycheck-verify-setup ()
   2749   "Check whether Flycheck can be used in this buffer.
   2750 
   2751 Display a new buffer listing all syntax checkers that could be
   2752 applicable in the current buffer.  For each syntax checkers,
   2753 possible problems are shown."
   2754   (interactive)
   2755   ;; Save to make sure checkers that only work on saved buffers will pass the
   2756   ;; verification
   2757   (when (and (buffer-file-name) (buffer-modified-p))
   2758     (save-buffer))
   2759 
   2760   (let* ((buffer (current-buffer))
   2761          (first-checker (flycheck-get-checker-for-buffer))
   2762          (valid-checkers
   2763           (remq first-checker
   2764                 (seq-filter #'flycheck-may-use-checker flycheck-checkers)))
   2765          (valid-next-checkers
   2766           (when first-checker
   2767             (seq-intersection valid-checkers
   2768                               (flycheck-all-next-checkers first-checker))))
   2769          (valid-remaining (seq-difference valid-checkers valid-next-checkers))
   2770          (other-checkers
   2771           (seq-difference (seq-filter #'flycheck-checker-supports-major-mode-p
   2772                                       flycheck-checkers)
   2773                           (cons first-checker valid-checkers))))
   2774 
   2775     ;; Print all applicable checkers for this buffer
   2776     (with-help-window "*Flycheck checkers*"
   2777       (with-current-buffer standard-output
   2778         (flycheck-verify-mode)
   2779 
   2780         (flycheck--verify-print-header "Syntax checkers for buffer " buffer)
   2781 
   2782         (if first-checker
   2783             (progn
   2784               (princ "First checker to run:\n\n")
   2785               (flycheck--verify-princ-checker first-checker buffer))
   2786           (insert (propertize
   2787                    "No checker to run in this buffer.\n\n"
   2788                    'face '(bold error))))
   2789 
   2790         (when valid-next-checkers
   2791           (princ
   2792            "Checkers that may run as part of the first checker's chain:\n\n")
   2793           (dolist (checker valid-next-checkers)
   2794             (flycheck--verify-princ-checker checker buffer)))
   2795 
   2796         (when valid-remaining
   2797           (princ "Checkers that could run if selected:\n\n")
   2798           (dolist (checker valid-remaining)
   2799             (flycheck--verify-princ-checker checker buffer nil 'with-select)))
   2800 
   2801         (when other-checkers
   2802           (princ
   2803            "Checkers that are compatible with this mode, \
   2804 but will not run until properly configured:\n\n")
   2805           (dolist (checker other-checkers)
   2806             (flycheck--verify-princ-checker checker buffer)))
   2807 
   2808         ;; If we have no checkers at all, that's worth mentioning
   2809         (unless (or first-checker valid-checkers other-checkers)
   2810           (insert (propertize
   2811                    "No checkers are available for this buffer.\n\n"
   2812                    'face '(bold error))))
   2813 
   2814         (let ((unregistered-checkers
   2815                (seq-difference (flycheck-defined-checkers) flycheck-checkers)))
   2816           (when unregistered-checkers
   2817             (insert (propertize
   2818                      "The following syntax checkers are not registered:\n"
   2819                      'face '(bold warning)))
   2820             (dolist (checker unregistered-checkers)
   2821               (princ "  - ")
   2822               (princ checker)
   2823               (princ "\n"))
   2824             (princ
   2825              "Try adding these syntax checkers to `flycheck-checkers'.\n\n")))
   2826 
   2827         (flycheck--verify-print-footer buffer)
   2828 
   2829         (setq-local revert-buffer-function
   2830                     (lambda (_ignore-auto _noconfirm)
   2831                       (with-current-buffer buffer (flycheck-verify-setup))))))))
   2832 
   2833 
   2834 ;;; Predicates for generic syntax checkers
   2835 (defun flycheck-buffer-saved-p (&optional buffer)
   2836   "Determine whether BUFFER is saved to a file.
   2837 
   2838 BUFFER is the buffer to check.  If omitted or nil, use the
   2839 current buffer as BUFFER.
   2840 
   2841 Return non-nil if the BUFFER is backed by a file, and not
   2842 modified, or nil otherwise."
   2843   (let ((file-name (buffer-file-name buffer)))
   2844     (and file-name (file-exists-p file-name) (not (buffer-modified-p buffer)))))
   2845 
   2846 
   2847 ;;; Extending generic checkers
   2848 (defun flycheck-remove-next-checker (checker next)
   2849   "After CHECKER remove a NEXT checker.
   2850 
   2851 CHECKER is a syntax checker symbol, from which to remove NEXT
   2852 checker.
   2853 
   2854 NEXT is a cons or a symbol, as documented in
   2855 `flycheck-add-next-checker'."
   2856   (unless (flycheck-valid-checker-p checker)
   2857     (error "%s is not a valid syntax checker" checker))
   2858   (let* ((next-symbol (flycheck--get-next-checker-symbol next)))
   2859     (setf
   2860      (flycheck-checker-get checker 'next-checkers)
   2861      (seq-remove
   2862       (lambda (next) (eq (flycheck--get-next-checker-symbol next) next-symbol))
   2863       (flycheck-checker-get checker 'next-checkers)))))
   2864 
   2865 (defun flycheck-add-next-checker (checker next &optional append)
   2866   "After CHECKER add a NEXT checker.
   2867 
   2868 CHECKER is a syntax checker symbol, to which to add NEXT checker.
   2869 
   2870 NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'.  NEXT-CHECKER is a
   2871 symbol denoting the syntax checker to run after CHECKER.  LEVEL
   2872 is an error level.  NEXT-CHECKER will only be used if there is no
   2873 current error whose level is more severe than LEVEL.  LEVEL may
   2874 also be t, in which case NEXT-CHECKER is used regardless of the
   2875 current errors.
   2876 
   2877 NEXT can also be a syntax checker symbol only, which is
   2878 equivalent to `(t . NEXT)'.
   2879 
   2880 NEXT-CHECKER is prepended before other next checkers, unless
   2881 APPEND is non-nil."
   2882   (unless (flycheck-valid-checker-p checker)
   2883     (error "%s is not a valid syntax checker" checker))
   2884   (flycheck-validate-next-checker next 'strict)
   2885   (flycheck-remove-next-checker checker next)
   2886   (let ((next-checkers (flycheck-checker-get checker 'next-checkers)))
   2887     (setf (flycheck-checker-get checker 'next-checkers)
   2888           (if append (append next-checkers (list next))
   2889             (cons next next-checkers)))))
   2890 
   2891 (defun flycheck-add-mode (checker mode)
   2892   "To CHECKER add a new major MODE.
   2893 
   2894 CHECKER and MODE are symbols denoting a syntax checker and a
   2895 major mode respectively.
   2896 
   2897 Add MODE to the `:modes' property of CHECKER, so that CHECKER
   2898 will be used in buffers with MODE."
   2899   (unless (flycheck-valid-checker-p checker)
   2900     (error "%s is not a valid syntax checker" checker))
   2901   (unless (symbolp mode)
   2902     (error "%s is not a symbol" mode))
   2903   (push mode (flycheck-checker-get checker 'modes)))
   2904 
   2905 
   2906 ;;; Generic syntax checks
   2907 (cl-defstruct (flycheck-syntax-check
   2908                (:constructor flycheck-syntax-check-new))
   2909   "Structure for storing syntax check state.
   2910 
   2911 Slots:
   2912 
   2913 `buffer'
   2914      The buffer being checked.
   2915 
   2916 `checker'
   2917      The syntax checker being used.
   2918 
   2919 `context'
   2920      The context object.
   2921 
   2922 `working-directory'
   2923      Working directory for the syntax checker. Serve as a value for
   2924      `default-directory' for a checker."
   2925   buffer checker context working-directory)
   2926 
   2927 (defun flycheck-syntax-check-start (syntax-check callback)
   2928   "Start a SYNTAX-CHECK with CALLBACK."
   2929   (let ((checker (flycheck-syntax-check-checker syntax-check))
   2930         (default-directory
   2931           (flycheck-syntax-check-working-directory syntax-check)))
   2932     (setf (flycheck-syntax-check-context syntax-check)
   2933           (funcall (flycheck-checker-get checker 'start) checker callback))))
   2934 
   2935 (defun flycheck-syntax-check-interrupt (syntax-check)
   2936   "Interrupt a SYNTAX-CHECK."
   2937   (let* ((checker (flycheck-syntax-check-checker syntax-check))
   2938          (interrupt-fn (flycheck-checker-get checker 'interrupt))
   2939          (context (flycheck-syntax-check-context syntax-check)))
   2940     (when interrupt-fn
   2941       (funcall interrupt-fn checker context))))
   2942 
   2943 
   2944 ;;; Syntax checking mode
   2945 
   2946 (defvar flycheck-mode-map
   2947   (let ((map (make-sparse-keymap)))
   2948     (define-key map flycheck-keymap-prefix flycheck-command-map)
   2949     ;; We place the menu under a custom menu key.  Since this menu key is not
   2950     ;; present in the menu of the global map, no top-level menu entry is added
   2951     ;; to the global menu bar.  However, it still appears on the mode line
   2952     ;; lighter.
   2953     (define-key map [menu-bar flycheck] flycheck-mode-menu-map)
   2954     map)
   2955   "Keymap of command `flycheck-mode'.")
   2956 
   2957 (defvar-local flycheck-old-next-error-function nil
   2958   "Remember the old `next-error-function'.")
   2959 
   2960 (defconst flycheck-hooks-alist
   2961   '(
   2962     ;; Handle events that may start automatic syntax checks
   2963     (after-save-hook        . flycheck-handle-save)
   2964     (after-change-functions . flycheck-handle-change)
   2965     ;; Handle events that may triggered pending deferred checks
   2966     (window-configuration-change-hook . flycheck-perform-deferred-syntax-check)
   2967     (post-command-hook                . flycheck-perform-deferred-syntax-check)
   2968     ;; Teardown Flycheck whenever the buffer state is about to get lost, to
   2969     ;; clean up temporary files and directories.
   2970     (kill-buffer-hook       . flycheck-teardown)
   2971     (change-major-mode-hook . flycheck-teardown)
   2972     (before-revert-hook     . flycheck-teardown)
   2973     ;; Update the error list if necessary
   2974     (post-command-hook . flycheck-error-list-update-source)
   2975     (post-command-hook . flycheck-error-list-highlight-errors)
   2976     ;; Display errors.  Show errors at point after commands (like movements) and
   2977     ;; when Emacs gets focus.  Cancel the display timer when Emacs looses focus
   2978     ;; (as there's no need to display errors if the user can't see them), and
   2979     ;; hide the error buffer (for large error messages) if necessary.  Note that
   2980     ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined
   2981     ;; hooks are perfectly ok we don't need a version guard here.  They'll just
   2982     ;; not work silently.
   2983     (post-command-hook . flycheck-display-error-at-point-soon)
   2984     (focus-in-hook     . flycheck-display-error-at-point-soon)
   2985     (focus-out-hook    . flycheck-cancel-error-display-error-at-point-timer)
   2986     (post-command-hook . flycheck-hide-error-buffer)
   2987     ;; Immediately show error popups when navigating to an error
   2988     (next-error-hook . flycheck-display-error-at-point))
   2989   "Hooks which Flycheck needs to hook in.
   2990 
   2991 The `car' of each pair is a hook variable, the `cdr' a function
   2992 to be added or removed from the hook variable if Flycheck mode is
   2993 enabled and disabled respectively.")
   2994 
   2995 ;;;###autoload
   2996 (define-minor-mode flycheck-mode
   2997   "Flycheck is a minor mode for on-the-fly syntax checking.
   2998 
   2999 In `flycheck-mode' the buffer is automatically syntax-checked
   3000 using the first suitable syntax checker from `flycheck-checkers'.
   3001 Use `flycheck-select-checker' to select a checker for the current
   3002 buffer manually.
   3003 
   3004 If you run into issues, use `\\[flycheck-verify-setup]' to get help.
   3005 
   3006 Flycheck supports many languages out of the box, and many
   3007 additional ones are available on MELPA.  Adding new ones is very
   3008 easy.  Complete documentation is available online at URL
   3009 `https://www.flycheck.org/en/latest/'.  Please report issues and
   3010 request features at URL `https://github.com/flycheck/flycheck'.
   3011 
   3012 Flycheck displays its status in the mode line.  In the default
   3013 configuration, it looks like this:
   3014 
   3015 `FlyC'     This buffer has not been checked yet.
   3016 `FlyC*'    Flycheck is running.  Expect results soon!
   3017 `FlyC:0'   Last check resulted in no errors and no warnings.
   3018 `FlyC:3|5' This buffer contains three errors and five warnings.
   3019            Use `\\[flycheck-list-errors]' to see the list.
   3020 `FlyC-'    Flycheck doesn't have a checker for this buffer.
   3021 
   3022 You may also see the following icons:
   3023 `FlyC!'    The checker crashed.
   3024 `FlyC.'    The last syntax check was manually interrupted.
   3025 `FlyC?'    The checker did something unexpected, like exiting with 1
   3026            but returning no errors.
   3027 
   3028 The following keybindings are available in `flycheck-mode':
   3029 
   3030 \\{flycheck-mode-map}
   3031 \(you can change the prefix by customizing
   3032 `flycheck-keymap-prefix')
   3033 
   3034 If called interactively, enable Flycheck mode if ARG is positive,
   3035 and disable it if ARG is zero or negative.  If called from Lisp,
   3036 also enable the mode if ARG is omitted or nil, and toggle it if
   3037 ARG is ‘toggle’; disable the mode otherwise."
   3038   :init-value nil
   3039   :keymap flycheck-mode-map
   3040   :lighter flycheck-mode-line
   3041   :after-hook (flycheck-buffer-automatically 'mode-enabled 'force-deferred)
   3042   (cond
   3043    (flycheck-mode
   3044     (flycheck-clear)
   3045 
   3046     (pcase-dolist (`(,hook . ,fn) (reverse flycheck-hooks-alist))
   3047       (add-hook hook fn nil 'local))
   3048 
   3049     (setq flycheck-old-next-error-function
   3050           (if flycheck-standard-error-navigation
   3051               next-error-function
   3052             :unset))
   3053     (when flycheck-standard-error-navigation
   3054       (setq next-error-function #'flycheck-next-error-function))
   3055 
   3056     ;; This hook must be added globally since otherwise we cannot
   3057     ;; detect a change from a buffer where Flycheck is enabled to a
   3058     ;; buffer where Flycheck is not enabled, and therefore cannot
   3059     ;; notice that there has been any change when the user switches
   3060     ;; back to the buffer where Flycheck is enabled.
   3061     (add-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
   3062    (t
   3063     (unless (eq flycheck-old-next-error-function :unset)
   3064       (setq next-error-function flycheck-old-next-error-function))
   3065 
   3066     (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist)
   3067       (remove-hook hook fn 'local))
   3068 
   3069     (flycheck-teardown))))
   3070 
   3071 
   3072 ;;; Syntax checker selection for the current buffer
   3073 (defun flycheck-get-checker-for-buffer ()
   3074   "Find the checker for the current buffer.
   3075 
   3076 Use the selected checker for the current buffer, if any,
   3077 otherwise search for the best checker from `flycheck-checkers'.
   3078 
   3079 Return checker if there is a checker for the current buffer, or
   3080 nil otherwise."
   3081   (if flycheck-checker
   3082       (when (flycheck-may-use-checker flycheck-checker)
   3083         flycheck-checker)
   3084     (seq-find #'flycheck-may-use-checker flycheck-checkers)))
   3085 
   3086 (defun flycheck-get-next-checker-for-buffer (checker)
   3087   "Get the checker to run after CHECKER for the current buffer."
   3088   (let ((next (seq-find #'flycheck-may-use-next-checker
   3089                         (flycheck-checker-get checker 'next-checkers))))
   3090     (when next
   3091       (if (symbolp next) next (cdr next)))))
   3092 
   3093 (defun flycheck-select-checker (checker)
   3094   "Select CHECKER for the current buffer.
   3095 
   3096 CHECKER is a syntax checker symbol (see `flycheck-checkers') or
   3097 nil.  In the former case, use CHECKER for the current buffer,
   3098 otherwise deselect the current syntax checker (if any) and use
   3099 automatic checker selection via `flycheck-checkers'.
   3100 
   3101 If called interactively prompt for CHECKER.  With prefix arg
   3102 deselect the current syntax checker and enable automatic
   3103 selection again.
   3104 
   3105 Set `flycheck-checker' to CHECKER and automatically start a new
   3106 syntax check if the syntax checker changed.
   3107 
   3108 CHECKER will be used, even if it is not contained in
   3109 `flycheck-checkers', or if it is disabled via
   3110 `flycheck-disabled-checkers'."
   3111   (interactive
   3112    (if current-prefix-arg
   3113        (list nil)
   3114      (list (flycheck-read-checker "Select checker: "
   3115                                   (flycheck-get-checker-for-buffer)))))
   3116   (when (not (eq checker flycheck-checker))
   3117     (unless (or (not checker) (flycheck-may-use-checker checker))
   3118       (flycheck-verify-checker checker)
   3119       (user-error "Can't use syntax checker %S in this buffer" checker))
   3120     (setq flycheck-checker checker)
   3121     (when flycheck-mode
   3122       (flycheck-buffer))))
   3123 
   3124 (defun flycheck--toggle-checker (checker enable)
   3125   "Enable or disable CHECKER for the current buffer.
   3126 
   3127 If ENABLE, re-enable CHECKER by removing it from the buffer-local
   3128 value of `flycheck-disabled-checkers'.  Otherwise, add the syntax
   3129 checker to the buffer-local value of `flycheck-disabled-checkers'."
   3130   (cond
   3131    (enable
   3132     ;; We must use `remq' instead of `delq', because we must _not_ modify the
   3133     ;; list.  Otherwise we could potentially modify the global default value,
   3134     ;; in case the list is the global default.
   3135     (when (memq checker flycheck-disabled-checkers)
   3136       (setq flycheck-disabled-checkers
   3137             (remq checker flycheck-disabled-checkers)))
   3138     (when (memq checker flycheck--automatically-disabled-checkers)
   3139       (setq flycheck--automatically-disabled-checkers
   3140             (remq checker flycheck--automatically-disabled-checkers))))
   3141    (t (unless (memq checker flycheck-disabled-checkers)
   3142         (push checker flycheck-disabled-checkers)))))
   3143 
   3144 (defun flycheck-disable-checker (checker &optional enable)
   3145   "Interactively disable CHECKER for the current buffer.
   3146 
   3147 Prompt for a syntax checker to disable, and add the syntax
   3148 checker to the buffer-local value of
   3149 `flycheck-disabled-checkers'.
   3150 
   3151 With non-nil ENABLE or with prefix arg, prompt for a disabled
   3152 syntax checker and re-enable it by removing it from the
   3153 buffer-local value of `flycheck-disabled-checkers'."
   3154   (declare
   3155    (interactive-only "Directly set `flycheck-disabled-checkers' instead"))
   3156   (interactive
   3157    (let* ((enable current-prefix-arg)
   3158           (candidates (if enable
   3159                           (append flycheck-disabled-checkers
   3160                                   flycheck--automatically-disabled-checkers)
   3161                         flycheck-checkers))
   3162           (prompt (if enable "Enable syntax checker: "
   3163                     "Disable syntax checker: ")))
   3164      (when (and enable (not candidates))
   3165        (user-error "No syntax checkers disabled in this buffer"))
   3166      (list (flycheck-read-checker prompt nil nil candidates) enable)))
   3167   (unless checker
   3168     (user-error "No syntax checker given"))
   3169   (flycheck--toggle-checker checker enable)
   3170   (flycheck-buffer))
   3171 
   3172 
   3173 ;;; Syntax checks for the current buffer
   3174 (defvar-local flycheck-current-syntax-check nil
   3175   "The current syntax check in the this buffer.")
   3176 (put 'flycheck-current-syntax-check 'permanent-local t)
   3177 
   3178 (defun flycheck-start-current-syntax-check (checker)
   3179   "Start a syntax check in the current buffer with CHECKER.
   3180 
   3181 Set `flycheck-current-syntax-check' accordingly."
   3182   ;; Allocate the current syntax check *before* starting it.  This allows for
   3183   ;; synchronous checks, which call the status callback immediately in their
   3184   ;; start function.
   3185   (let* ((check
   3186           (flycheck-syntax-check-new
   3187            :buffer (current-buffer)
   3188            :checker checker
   3189            :context nil
   3190            :working-directory (flycheck-compute-working-directory checker)))
   3191          (callback (flycheck-buffer-status-callback check)))
   3192     (setq flycheck-current-syntax-check check)
   3193     (flycheck-report-status 'running)
   3194     (flycheck-syntax-check-start check callback)))
   3195 
   3196 (defun flycheck-running-p ()
   3197   "Determine whether a syntax check is running in the current buffer."
   3198   (not (null flycheck-current-syntax-check)))
   3199 
   3200 (defun flycheck-stop ()
   3201   "Stop any ongoing syntax check in the current buffer."
   3202   (when (flycheck-running-p)
   3203     (flycheck-syntax-check-interrupt flycheck-current-syntax-check)
   3204     ;; Remove the current syntax check, to reset Flycheck into a non-running
   3205     ;; state, and to make `flycheck-report-buffer-checker-status' ignore any
   3206     ;; status reports from the current syntax check.
   3207     (setq flycheck-current-syntax-check nil)
   3208     (flycheck-report-status 'interrupted)))
   3209 
   3210 (defun flycheck-buffer-status-callback (syntax-check)
   3211   "Create a status callback for SYNTAX-CHECK in the current buffer."
   3212   (lambda (&rest args)
   3213     (apply #'flycheck-report-buffer-checker-status
   3214            syntax-check args)))
   3215 
   3216 (defun flycheck-buffer ()
   3217   "Start checking syntax in the current buffer.
   3218 
   3219 Get a syntax checker for the current buffer with
   3220 `flycheck-get-checker-for-buffer', and start it."
   3221   (interactive)
   3222   (flycheck-clean-deferred-check)
   3223   (if flycheck-mode
   3224       (unless (flycheck-running-p)
   3225         ;; Clear error list and mark all overlays for deletion.  We do not
   3226         ;; delete all overlays immediately to avoid excessive re-displays and
   3227         ;; flickering, if the same errors gets highlighted again after the check
   3228         ;; completed.
   3229         (run-hooks 'flycheck-before-syntax-check-hook)
   3230         (flycheck-clear-errors)
   3231         (flycheck-mark-all-overlays-for-deletion)
   3232         (condition-case err
   3233             (let* ((checker (flycheck-get-checker-for-buffer)))
   3234               (if checker
   3235                   (flycheck-start-current-syntax-check checker)
   3236                 (flycheck-clear)
   3237                 (flycheck-report-status 'no-checker)))
   3238           (error
   3239            (flycheck-report-failed-syntax-check)
   3240            (signal (car err) (cdr err)))))
   3241     (user-error "Flycheck mode disabled")))
   3242 
   3243 (defun flycheck-report-buffer-checker-status
   3244     (syntax-check status &optional data)
   3245   "In BUFFER, report a SYNTAX-CHECK STATUS with DATA.
   3246 
   3247 SYNTAX-CHECK is the `flycheck-syntax-check' which reported
   3248 STATUS.  STATUS denotes the status of CHECKER, with an optional
   3249 DATA.  STATUS may be one of the following symbols:
   3250 
   3251 `errored'
   3252      The syntax checker has errored.  DATA is an optional error
   3253      message.
   3254 
   3255      This report finishes the current syntax check.
   3256 
   3257 `interrupted'
   3258      The syntax checker was interrupted.  DATA is ignored.
   3259 
   3260      This report finishes the current syntax check.
   3261 
   3262 `finished'
   3263      The syntax checker has finished with a proper error report
   3264      for the current buffer.  DATA is the (potentially empty)
   3265      list of `flycheck-error' objects reported by the syntax
   3266      check.
   3267 
   3268      This report finishes the current syntax check.
   3269 
   3270 `suspicious'
   3271      The syntax checker encountered a suspicious state, which the
   3272      user needs to be informed about.  DATA is an optional
   3273      message.
   3274 
   3275 A syntax checker _must_ report a status at least once with any
   3276 symbol that finishes the current syntax checker.  Otherwise
   3277 Flycheck gets stuck with the current syntax check.
   3278 
   3279 If CHECKER is not the currently used syntax checker in
   3280 `flycheck-current-syntax-check', the status report is largely
   3281 ignored.  Notably, any errors reported by the checker are
   3282 discarded."
   3283   (let ((buffer (flycheck-syntax-check-buffer syntax-check)))
   3284     ;; Ignore the status report if the buffer is gone, or if this syntax check
   3285     ;; isn't the current one in buffer (which can happen if this is an old
   3286     ;; report of an interrupted syntax check, and a new syntax check was started
   3287     ;; since this check was interrupted)
   3288     (when (and (buffer-live-p buffer)
   3289                (eq syntax-check
   3290                    (buffer-local-value 'flycheck-current-syntax-check buffer)))
   3291       (with-current-buffer buffer
   3292         (let ((checker (flycheck-syntax-check-checker syntax-check)))
   3293           (pcase status
   3294             ((or `errored `interrupted)
   3295              (flycheck-report-failed-syntax-check status)
   3296              (when (eq status 'errored)
   3297                ;; In case of error, show the error message
   3298                (message "Error from syntax checker %s: %s"
   3299                         checker (or data "UNKNOWN!"))))
   3300             (`suspicious
   3301              (when flycheck-mode
   3302                (message "Suspicious state from syntax checker %s: %s"
   3303                         checker (or data "UNKNOWN!")))
   3304              (flycheck-report-status 'suspicious))
   3305             (`finished
   3306              (when flycheck-mode
   3307                ;; Only report errors from the checker if Flycheck Mode is
   3308                ;; still enabled.
   3309                (flycheck-finish-current-syntax-check
   3310                 data
   3311                 (flycheck-syntax-check-working-directory syntax-check))))
   3312             (_
   3313              (error "Unknown status %s from syntax checker %s"
   3314                     status checker))))))))
   3315 
   3316 (defun flycheck-finish-current-syntax-check (errors working-dir)
   3317   "Finish the current syntax-check in the current buffer with ERRORS.
   3318 
   3319 ERRORS is a list of `flycheck-error' objects reported by the
   3320 current syntax check in `flycheck-current-syntax-check'.
   3321 
   3322 Report all ERRORS and potentially start any next syntax checkers.
   3323 
   3324 If the current syntax checker reported excessive errors, it is
   3325 disabled via `flycheck-disable-excessive-checker' for subsequent
   3326 syntax checks.
   3327 
   3328 Relative file names in ERRORS will be expanded relative to
   3329 WORKING-DIR."
   3330   (let* ((syntax-check flycheck-current-syntax-check)
   3331          (checker (flycheck-syntax-check-checker syntax-check))
   3332          (errors (flycheck-relevant-errors
   3333                   (flycheck-fill-and-expand-error-file-names
   3334                    (flycheck-filter-errors
   3335                     (flycheck-assert-error-list-p errors) checker)
   3336                    working-dir))))
   3337     (unless (flycheck-disable-excessive-checker checker errors)
   3338       (flycheck-report-current-errors errors))
   3339     (let ((next-checker (flycheck-get-next-checker-for-buffer checker)))
   3340       (if next-checker
   3341           (flycheck-start-current-syntax-check next-checker)
   3342         (setq flycheck-current-syntax-check nil)
   3343         (flycheck-report-status 'finished)
   3344         ;; Delete overlays only after the very last checker has run, to avoid
   3345         ;; flickering on intermediate re-displays
   3346         (flycheck-delete-marked-overlays)
   3347         (flycheck-error-list-refresh)
   3348         (run-hooks 'flycheck-after-syntax-check-hook)
   3349         (when (and flycheck-auto-display-errors-after-checking
   3350                    (eq (current-buffer) (window-buffer)))
   3351           (flycheck-display-error-at-point))
   3352         ;; Immediately try to run any pending deferred syntax check, which
   3353         ;; were triggered by intermediate automatic check event, to make sure
   3354         ;; that we quickly refine outdated error information
   3355         (flycheck-perform-deferred-syntax-check)))))
   3356 
   3357 (defun flycheck-disable-excessive-checker (checker errors)
   3358   "Disable CHECKER if it reported excessive ERRORS.
   3359 
   3360 If ERRORS has more items than `flycheck-checker-error-threshold',
   3361 add CHECKER to `flycheck--automatically-disabled-checkers', and
   3362 show a warning.
   3363 
   3364 Return t when CHECKER was disabled, or nil otherwise."
   3365   (when (and flycheck-checker-error-threshold
   3366              (> (length errors) flycheck-checker-error-threshold))
   3367     ;; Disable CHECKER for this buffer
   3368     ;; (`flycheck--automatically-disabled-checkers' is a local variable).
   3369     (lwarn '(flycheck syntax-checker) :warning
   3370            (substitute-command-keys
   3371             "Syntax checker %s reported too many errors (%s) and is disabled.
   3372 Use `\\[customize-variable] RET flycheck-checker-error-threshold' to
   3373 change the threshold or `\\[universal-argument] \
   3374 \\[flycheck-disable-checker]' to re-enable the checker.")
   3375            checker (length errors))
   3376     (push checker flycheck--automatically-disabled-checkers)
   3377     t))
   3378 
   3379 (defun flycheck-clear (&optional shall-interrupt)
   3380   "Clear all errors in the current buffer.
   3381 
   3382 With prefix arg or SHALL-INTERRUPT non-nil, also interrupt the
   3383 current syntax check."
   3384   (interactive "P")
   3385   (when shall-interrupt
   3386     (flycheck-stop))
   3387   (flycheck-delete-all-overlays)
   3388   (flycheck-clear-errors)
   3389   (flycheck-clear-displayed-error-messages)
   3390   (flycheck-error-list-refresh)
   3391   (flycheck-hide-error-buffer))
   3392 
   3393 (defun flycheck--empty-variables ()
   3394   "Empty variables used by Flycheck."
   3395   (kill-local-variable 'flycheck--file-truename-cache)
   3396   (kill-local-variable 'flycheck--idle-trigger-timer)
   3397   (kill-local-variable 'flycheck--idle-trigger-conditions)
   3398   (kill-local-variable 'flycheck--last-error-display-tick))
   3399 
   3400 (defun flycheck-teardown (&optional ignore-global)
   3401   "Teardown Flycheck in the current buffer.
   3402 
   3403 Completely clear the whole Flycheck state.  Remove overlays, kill
   3404 running checks, and empty all variables used by Flycheck.
   3405 
   3406 Unless optional argument IGNORE-GLOBAL is non-nil, check to see
   3407 if no more Flycheck buffers remain (aside from the current
   3408 buffer), and if so then clean up global hooks."
   3409   (flycheck-safe-delete-temporaries)
   3410   (flycheck-stop)
   3411   (flycheck-clean-deferred-check)
   3412   (flycheck-clear)
   3413   (flycheck-cancel-error-display-error-at-point-timer)
   3414   (flycheck--clear-idle-trigger-timer)
   3415   (flycheck--empty-variables)
   3416   (unless (or ignore-global
   3417               (seq-some (lambda (buf)
   3418                           (and (not (equal buf (current-buffer)))
   3419                                (buffer-local-value 'flycheck-mode buf)))
   3420                         (buffer-list)))
   3421     (flycheck-global-teardown 'ignore-local)))
   3422 
   3423 
   3424 ;;; Automatic syntax checking in a buffer
   3425 (defun flycheck-may-check-automatically (&rest conditions)
   3426   "Determine whether the buffer may be checked under one of CONDITIONS.
   3427 
   3428 Read-only buffers may never be checked automatically.
   3429 
   3430 If CONDITIONS are given, determine whether syntax may be checked
   3431 under at least one of them, according to
   3432 `flycheck-check-syntax-automatically'."
   3433   (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p)))
   3434        (file-exists-p default-directory)
   3435        (or (not conditions)
   3436            (seq-some
   3437             (lambda (condition)
   3438               (memq condition flycheck-check-syntax-automatically))
   3439             conditions))))
   3440 
   3441 (defvar-local flycheck--idle-trigger-timer nil
   3442   "Timer used to trigger a syntax check after an idle delay.")
   3443 
   3444 (defvar-local flycheck--idle-trigger-conditions nil
   3445   "List of conditions under which an idle syntax check will be triggered.
   3446 This will be some subset of the allowable values for
   3447 `flycheck-check-syntax-automatically'.
   3448 
   3449 For example, if the user switches to a buffer and then makes an
   3450 edit, this list will have the values `idle-change' and
   3451 `idle-buffer-switch' in it, at least until the idle timer
   3452 expires.")
   3453 
   3454 (defun flycheck-buffer-automatically (&optional condition force-deferred)
   3455   "Automatically check syntax at CONDITION.
   3456 
   3457 Syntax is not checked if `flycheck-may-check-automatically'
   3458 returns nil for CONDITION.  (CONDITION may be a single condition
   3459 or a list of them.)
   3460 
   3461 The syntax check is deferred if FORCE-DEFERRED is non-nil, or if
   3462 `flycheck-must-defer-check' returns t."
   3463   (when (and flycheck-mode (if (listp condition)
   3464                                (apply #'flycheck-may-check-automatically
   3465                                       condition)
   3466                              (flycheck-may-check-automatically condition)))
   3467     (flycheck--clear-idle-trigger-timer)
   3468     (setq flycheck--idle-trigger-conditions nil)
   3469     (if (or force-deferred (flycheck-must-defer-check))
   3470         (flycheck-buffer-deferred)
   3471       (with-demoted-errors "Error while checking syntax automatically: %S"
   3472         (flycheck-buffer)))))
   3473 
   3474 (defun flycheck--clear-idle-trigger-timer ()
   3475   "Clear the idle trigger timer."
   3476   (when flycheck--idle-trigger-timer
   3477     (cancel-timer flycheck--idle-trigger-timer)
   3478     (setq flycheck--idle-trigger-timer nil)))
   3479 
   3480 (defun flycheck--handle-idle-trigger (buffer)
   3481   "Run a syntax check in BUFFER if appropriate.
   3482 This function is called by `flycheck--idle-trigger-timer'."
   3483   (let ((current-buffer (current-buffer)))
   3484     (when (buffer-live-p buffer)
   3485       (with-current-buffer buffer
   3486         (unless (or flycheck-buffer-switch-check-intermediate-buffers
   3487                     (eq buffer current-buffer))
   3488           (setq flycheck--idle-trigger-conditions
   3489                 (delq 'idle-buffer-switch
   3490                       flycheck--idle-trigger-conditions)))
   3491         (when flycheck--idle-trigger-conditions
   3492           (flycheck-buffer-automatically flycheck--idle-trigger-conditions)
   3493           (setq flycheck--idle-trigger-conditions nil))))))
   3494 
   3495 (defun flycheck-handle-change (beg end _len)
   3496   "Handle a buffer change between BEG and END.
   3497 
   3498 BEG and END mark the beginning and end of the change text.  _LEN
   3499 is ignored.
   3500 
   3501 Start a syntax check if a new line has been inserted into the
   3502 buffer."
   3503   ;; Save and restore the match data, as recommended in (elisp)Change Hooks
   3504   (save-match-data
   3505     (when flycheck-mode
   3506       (if (string-match-p (rx "\n") (buffer-substring beg end))
   3507           (flycheck-buffer-automatically 'new-line 'force-deferred)
   3508         (when (memq 'idle-change flycheck-check-syntax-automatically)
   3509           (flycheck--clear-idle-trigger-timer)
   3510           (cl-pushnew 'idle-change flycheck--idle-trigger-conditions)
   3511           (setq flycheck--idle-trigger-timer
   3512                 (run-at-time flycheck-idle-change-delay nil
   3513                              #'flycheck--handle-idle-trigger
   3514                              (current-buffer))))))))
   3515 
   3516 (defvar flycheck--last-buffer (current-buffer)
   3517   "The current buffer or the buffer that was previously current.
   3518 This is usually equal to the current buffer, unless the user just
   3519 switched buffers.  After a buffer switch, it is the previous
   3520 buffer.")
   3521 
   3522 (defun flycheck-handle-buffer-switch ()
   3523   "Handle a possible switch to another buffer.
   3524 
   3525 If a buffer switch actually happened, schedule a syntax check."
   3526   ;; Switching buffers here is weird, but unfortunately necessary.  It
   3527   ;; turns out that `with-temp-buffer' triggers
   3528   ;; `buffer-list-update-hook' twice, and the value of
   3529   ;; `current-buffer' is bogus in one of those triggers (the one just
   3530   ;; after the temp buffer is killed).  If we rely on the bogus value,
   3531   ;; Flycheck will think that the user is switching back and forth
   3532   ;; between different buffers during the `with-temp-buffer' call
   3533   ;; (note: two different normal buffers, not the current buffer and
   3534   ;; the temp buffer!), and that would trigger spurious syntax checks.
   3535   ;; It seems that reading (window-buffer) gets us the correct current
   3536   ;; buffer in all important real-life situations (although it doesn't
   3537   ;; necessarily catch uses of `set-buffer').
   3538   (with-current-buffer (window-buffer)
   3539     (unless (or (equal flycheck--last-buffer (current-buffer))
   3540                 ;; Don't bother keeping track of changes to and from
   3541                 ;; the minibuffer, as they will never require us to
   3542                 ;; run a syntax check.
   3543                 (minibufferp))
   3544       (setq flycheck--last-buffer (current-buffer))
   3545       (when (and flycheck-mode
   3546                  (memq 'idle-buffer-switch flycheck-check-syntax-automatically))
   3547         (flycheck--clear-idle-trigger-timer)
   3548         (cl-pushnew 'idle-buffer-switch flycheck--idle-trigger-conditions)
   3549         (setq flycheck--idle-trigger-timer
   3550               (run-at-time flycheck-idle-buffer-switch-delay nil
   3551                            #'flycheck--handle-idle-trigger
   3552                            (current-buffer)))))))
   3553 
   3554 (defun flycheck-handle-save ()
   3555   "Handle a save of the buffer."
   3556   (flycheck-buffer-automatically 'save))
   3557 
   3558 
   3559 ;;; Deferred syntax checking
   3560 (defvar-local flycheck-deferred-syntax-check nil
   3561   "If non-nil, a deferred syntax check is pending.")
   3562 
   3563 (defun flycheck-must-defer-check ()
   3564   "Determine whether the syntax check has to be deferred.
   3565 
   3566 A check has to be deferred if the buffer is not visible, or if the buffer is
   3567 currently being reverted.
   3568 
   3569 Return t if the check is to be deferred, or nil otherwise."
   3570   (or (not (get-buffer-window))
   3571       ;; We defer the syntax check if Flycheck is already running, to
   3572       ;; immediately start a new syntax check after the current one finished,
   3573       ;; because the result of the current check will most likely be outdated by
   3574       ;; the time it is finished.
   3575       (flycheck-running-p)
   3576       ;; We must defer checks while a buffer is being reverted, to avoid race
   3577       ;; conditions while the buffer contents are being restored.
   3578       revert-buffer-in-progress-p))
   3579 
   3580 (defun flycheck-deferred-check-p ()
   3581   "Determine whether the current buffer has a deferred check.
   3582 
   3583 Return t if so, or nil otherwise."
   3584   flycheck-deferred-syntax-check)
   3585 
   3586 (defun flycheck-buffer-deferred ()
   3587   "Defer syntax check for the current buffer."
   3588   (setq flycheck-deferred-syntax-check t))
   3589 
   3590 (defun flycheck-clean-deferred-check ()
   3591   "Clean a deferred syntax checking state."
   3592   (setq flycheck-deferred-syntax-check nil))
   3593 
   3594 (defun flycheck-perform-deferred-syntax-check ()
   3595   "Perform the deferred syntax check."
   3596   (when (flycheck-deferred-check-p)
   3597     (flycheck-clean-deferred-check)
   3598     (flycheck-buffer-automatically)))
   3599 
   3600 
   3601 ;;; Syntax checking in all buffers
   3602 (defun flycheck-may-enable-mode ()
   3603   "Determine whether Flycheck mode may be enabled.
   3604 
   3605 Flycheck mode is not enabled for
   3606 
   3607 - the minibuffer,
   3608 - `fundamental-mode'
   3609 - major modes whose `mode-class' property is `special',
   3610 - ephemeral buffers (see `flycheck-ephemeral-buffer-p'),
   3611 - encrypted buffers (see `flycheck-encrypted-buffer-p'),
   3612 - remote files (see `file-remote-p'),
   3613 - and major modes excluded by `flycheck-global-modes'.
   3614 
   3615 Return non-nil if Flycheck mode may be enabled, and nil
   3616 otherwise."
   3617   (and (pcase flycheck-global-modes
   3618          ;; Whether `major-mode' is disallowed by `flycheck-global-modes'
   3619          (`t t)
   3620          (`(not . ,modes) (not (memq major-mode modes)))
   3621          (modes (memq major-mode modes)))
   3622        (not (or (minibufferp)
   3623                 (eq major-mode 'fundamental-mode)
   3624                 (eq (get major-mode 'mode-class) 'special)
   3625                 (flycheck-ephemeral-buffer-p)
   3626                 (flycheck-encrypted-buffer-p)
   3627                 (and (buffer-file-name)
   3628                      (file-remote-p (buffer-file-name) 'method))))))
   3629 
   3630 (defun flycheck-mode-on-safe ()
   3631   "Enable command `flycheck-mode' if it is safe to do so.
   3632 
   3633 Command `flycheck-mode' is only enabled if
   3634 `flycheck-may-enable-mode' returns a non-nil result."
   3635   (when (flycheck-may-enable-mode)
   3636     (flycheck-mode)))
   3637 
   3638 ;;;###autoload
   3639 (define-globalized-minor-mode global-flycheck-mode flycheck-mode
   3640   flycheck-mode-on-safe
   3641   :init-value nil
   3642   :group 'flycheck)
   3643 
   3644 (defun flycheck-global-teardown (&optional ignore-local)
   3645   "Teardown Flycheck in all buffers.
   3646 
   3647 Completely clear the whole Flycheck state in all buffers, stop
   3648 all running checks, remove all temporary files, and empty all
   3649 variables of Flycheck.
   3650 
   3651 Also remove global hooks.  (If optional argument IGNORE-LOCAL is
   3652 non-nil, then only do this and skip per-buffer teardown.)"
   3653   (unless ignore-local
   3654     (dolist (buffer (buffer-list))
   3655       (when (buffer-live-p buffer)
   3656         (with-current-buffer buffer
   3657           (when flycheck-mode
   3658             (flycheck-teardown 'ignore-global))))))
   3659   (remove-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch))
   3660 
   3661 ;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any
   3662 ;; pending temporary files.
   3663 (add-hook 'kill-emacs-hook #'flycheck-global-teardown)
   3664 
   3665 
   3666 ;;; Errors from syntax checks
   3667 (cl-defstruct (flycheck-error
   3668                (:constructor nil)
   3669                (:constructor
   3670                 flycheck-error-new
   3671                 (&key
   3672                  line column end-line end-column
   3673                  buffer checker filename message level id group
   3674                  &aux (-end-line end-line) (-end-column end-column)))
   3675                (:constructor
   3676                 flycheck-error-new-at
   3677                 (line
   3678                  column
   3679                  &optional level message
   3680                  &key end-line end-column checker id group
   3681                  (filename (buffer-file-name)) (buffer (current-buffer))
   3682                  &aux (-end-line end-line) (-end-column end-column)))
   3683                (:constructor
   3684                 flycheck-error-new-at-pos
   3685                 (pos
   3686                  &optional level message
   3687                  &key end-pos checker id group
   3688                  (filename (buffer-file-name)) (buffer (current-buffer))
   3689                  &aux
   3690                  ((line . column)
   3691                   (if pos (flycheck-line-column-at-pos pos)
   3692                     '(nil . nil)))
   3693                  ((-end-line . -end-column)
   3694                   (if end-pos (flycheck-line-column-at-pos end-pos)
   3695                     '(nil . nil))))))
   3696   "Structure representing an error reported by a syntax checker.
   3697 Slots:
   3698 
   3699 `buffer'
   3700      The buffer that the error was reported for, as buffer object.
   3701 
   3702 `checker'
   3703      The syntax checker which reported this error, as symbol.
   3704 
   3705 `filename'
   3706      The file name the error refers to, as string.
   3707 
   3708 `line'
   3709      The line on which the error starts, as number.
   3710 
   3711 `column' (optional)
   3712      The column at which the error starts, as number.
   3713 
   3714      For compatibility with external tools and unlike Emacs
   3715      itself (e.g. in Compile Mode) Flycheck uses _1-based_
   3716      columns: The first character on a line is column 1.
   3717 
   3718      Occasionally some tools try to proactively adapt to Emacs
   3719      and emit 0-based columns automatically.  In these cases, the
   3720      columns must be adjusted for Flycheck, see
   3721      `flycheck-increment-error-columns'.
   3722 
   3723      If nil, the whole line is highlighted.
   3724 
   3725 `end-line' (optional)
   3726     The line on which the error ends.  If nil, this is computed according to
   3727     `flycheck-highlighting-mode'.
   3728 
   3729 `end-column'
   3730     The column at which the error ends.  If nil, this is computed according to
   3731     `flycheck-highlighting-mode'.  Error intervals are right-open: the
   3732     end-column points to the first character not included in the error.  For
   3733     example, 1:1 is an empty range. and in \"line-number-at-pos\", the range
   3734     6:12 covers the word \"number\".
   3735 
   3736 `message' (optional)
   3737      The error message as a string, if any.
   3738 
   3739 `level'
   3740      The error level, as either `info', `warning' or `error'.
   3741 
   3742 `id' (optional)
   3743      An ID identifying the kind of error.
   3744 
   3745 `group' (optional)
   3746      A symbol identifying the group the error belongs to.
   3747 
   3748      Some tools will emit multiple errors that relate to the same
   3749      issue (e.g., lifetime errors in Rust).  All related errors
   3750      collected by a checker should have the same `group` value,
   3751      in order to be able to present them to the user.
   3752 
   3753      See `flycheck-related-errors`."
   3754   buffer checker filename line column message level id group
   3755   ;; The fields below are at the end of the record to preserve backwards
   3756   ;; compatibility; see https://github.com/flycheck/flycheck/pull/1400 and
   3757   ;; https://lists.gnu.org/archive/html/emacs-devel/2018-07/msg00436.html
   3758   -end-line -end-column)
   3759 
   3760 ;; These accessors are defined for backwards compatibility
   3761 ;; FIXME: Clean up once package.el learns how to recompile dependencies.
   3762 
   3763 (defun flycheck-error-end-line (err)
   3764   "Return the end line of a Flycheck error ERR."
   3765   (condition-case nil (flycheck-error--end-line err)
   3766     (args-out-of-range nil)))
   3767 
   3768 (defun flycheck-error-end-column (err)
   3769   "Return the end column of a Flycheck error ERR."
   3770   (condition-case nil (flycheck-error--end-column err)
   3771     (args-out-of-range nil)))
   3772 
   3773 (defun flycheck-error--set-end-line (err line)
   3774   "Set the end line of a Flycheck error ERR to LINE."
   3775   (condition-case nil (setf (flycheck-error--end-line err) line)
   3776     (args-out-of-range nil)))
   3777 
   3778 (defun flycheck-error--set-end-column (err column)
   3779   "Set the end column of a Flycheck error ERR to COLUMN."
   3780   (condition-case nil (setf (flycheck-error--end-column err) column)
   3781     (args-out-of-range nil)))
   3782 
   3783 (gv-define-simple-setter flycheck-error-end-line
   3784                          flycheck-error--set-end-line)
   3785 (gv-define-simple-setter flycheck-error-end-column
   3786                          flycheck-error--set-end-column)
   3787 
   3788 (defmacro flycheck-error-with-buffer (err &rest forms)
   3789   "Switch to the buffer of ERR and evaluate FORMS.
   3790 
   3791 If the buffer of ERR is not live, FORMS are not evaluated."
   3792   (declare (indent 1) (debug t))
   3793   `(when (buffer-live-p (flycheck-error-buffer ,err))
   3794      (with-current-buffer (flycheck-error-buffer ,err)
   3795        ,@forms)))
   3796 
   3797 (defun flycheck--exact-region (err)
   3798   "Get the region of ERR, if ERR specifies a range.
   3799 
   3800 Return a cons cell `(BEG . END)'.  If the input range is empty,
   3801 it is expanded to cover at least one character so that END is
   3802 always greater than BEG.  If ERR doesn't specify an end-column
   3803 return nil."
   3804   (if-let* ((line (flycheck-error-line err))
   3805             (column (flycheck-error-column err))
   3806             (end-line (or (flycheck-error-end-line err) line))
   3807             (end-column (flycheck-error-end-column err)))
   3808       ;; Ignoring fields speeds up calls to `line-end-position'.
   3809       (let* ((inhibit-field-text-motion t)
   3810              (beg (flycheck-line-column-to-position line column))
   3811              (end (flycheck-line-column-to-position end-line end-column)))
   3812         (cond
   3813          ((< beg end) (cons beg end))
   3814          ((= end (point-max)) (cons (1- end) end))
   3815          (t (cons end (1+ end)))))))
   3816 
   3817 (defun flycheck--line-region (pos)
   3818   "Get the line region of position POS.
   3819 
   3820 Return a cons cell `(BEG . END)' where BEG is the first
   3821 non-whitespace character on the line ERR refers to, and END the
   3822 end of the line."
   3823   (save-excursion
   3824     (goto-char pos)
   3825     (forward-line 0)
   3826     (let ((bol (point))
   3827           (end (line-end-position)))
   3828       ;; Move to the beginning of this line's indentation, similar to
   3829       ;; `back-to-indentation'
   3830       (skip-syntax-forward " " end)
   3831       (backward-prefix-chars)
   3832       ;; If the current line is blank, highlight it in full; if it's
   3833       ;; empty, include the previous line break character(s) to have
   3834       ;; any region at all (when called with 0, `line-end-position'
   3835       ;; gives us the end of the previous line).
   3836       (cons (if (eolp) (if (= bol end) (line-end-position 0) bol) (point))
   3837             end))))
   3838 
   3839 (defun flycheck--column-region (pos)
   3840   "Get the column region of position POS.
   3841 
   3842 Return a cons cell `(BEG . END)' where BEG is the character
   3843 before the column, and END the actual column."
   3844   (save-excursion
   3845     (goto-char pos)
   3846     ;; (eobp): No enough lines in the buffer
   3847     (if (eobp) (cons (1- (point-max)) (point-max))
   3848       (cons pos (1+ pos)))))
   3849 
   3850 (defun flycheck-bounds-of-thing-at-point (thing pos)
   3851   "Get the region of THING at position POS.
   3852 
   3853 THING is a understood by `thing-at-point'.
   3854 
   3855 Return a cons cell `(BEG . END)' where BEG is the beginning of
   3856 the THING at the column, and END the end of the THING."
   3857   (save-excursion
   3858     (goto-char pos)
   3859     (bounds-of-thing-at-point thing)))
   3860 
   3861 (defun flycheck--approximate-region (err mode)
   3862   "Compute the region of ERR based on MODE and ERR's line and column."
   3863   ;; Ignoring fields speeds up calls to `line-end-position'.
   3864   (let* ((inhibit-field-text-motion t)
   3865          (line (flycheck-error-line err))
   3866          (column (flycheck-error-column err))
   3867          (beg (flycheck-line-column-to-position line (or column 1))))
   3868     (if (or (null column)
   3869             (eq mode 'lines))
   3870         (flycheck--line-region beg)
   3871       (or (pcase mode
   3872             (`symbols
   3873              ;; Ensure that we're on a word or symbol.  See
   3874              ;; https://github.com/flycheck/flycheck/issues/1519
   3875              (and (<= (point-min) beg) (< beg (point-max))
   3876                   (memq (char-syntax (char-after beg)) '(?w ?_))
   3877                   (flycheck-bounds-of-thing-at-point 'symbol beg)))
   3878             (`sexps
   3879              (flycheck-bounds-of-thing-at-point 'sexp beg)))
   3880           (flycheck--column-region beg)))))
   3881 
   3882 (defun flycheck-error-region-for-mode (err mode)
   3883   "Get the region of ERR for the highlighting MODE.
   3884 
   3885 ERR is a Flycheck error.  If its position is fully specified, use
   3886 that to compute a region; otherwise, use MODE, as documented in
   3887 `flycheck-highlighting-mode'.  If MODE is nil, signal an error."
   3888   (flycheck-error-with-buffer err
   3889     (save-restriction
   3890       (widen)
   3891       (or (flycheck--exact-region err)
   3892           (flycheck--approximate-region err mode)))))
   3893 
   3894 (defun flycheck-error-pos (err)
   3895   "Get the buffer position of ERR.
   3896 
   3897 ERR is a Flycheck error whose position to get.
   3898 
   3899 The error position is the error column, or the first
   3900 non-whitespace character of the error line, if ERR has no error column."
   3901   (car (flycheck-error-region-for-mode
   3902         err flycheck-highlighting-mode)))
   3903 
   3904 (defun flycheck-error-format-snippet (err &optional max-length)
   3905   "Extract the text that ERR refers to from the buffer.
   3906 
   3907 Newlines and blanks are replaced by single spaces.  If ERR
   3908 doesn't include an end-position, return nil.
   3909 
   3910 MAX-LENGTH is how many characters to read from the buffer, at
   3911 most.  It defaults to 20."
   3912   (flycheck-error-with-buffer err
   3913     (save-restriction
   3914       (widen)
   3915       (pcase (flycheck--exact-region err)
   3916         (`(,beg . ,end)
   3917          (truncate-string-to-width
   3918           (replace-regexp-in-string
   3919            "\\s-+" " " (buffer-substring beg (min end (point-max))))
   3920           (or max-length 20) nil nil t))))))
   3921 
   3922 (defun flycheck-error-format-message-and-id (err &optional include-snippet)
   3923   "Format the message and id of ERR as human-readable string.
   3924 
   3925 If INCLUDE-SNIPPET is non-nil, prepend the message with a snippet
   3926 of the text that the error applies to (such text can only be
   3927 determined if the error contains a full span, not just a
   3928 beginning position)."
   3929   (let* ((id (flycheck-error-id err))
   3930          (fname (flycheck-error-filename err))
   3931          (other-file-p (and fname (not (equal fname (buffer-file-name))))))
   3932     (concat (and other-file-p (format "In %S:\n" (file-relative-name fname)))
   3933             (and include-snippet
   3934                  (when-let* ((snippet (flycheck-error-format-snippet err)))
   3935                    (format-message "`%s': " snippet)))
   3936             (or (flycheck-error-message err)
   3937                 (format "Unknown %S" (flycheck-error-level err)))
   3938             (and id (format " [%s]" id)))))
   3939 
   3940 (defun flycheck-error-format-position (err)
   3941   "Format the position of ERR as a human-readable string."
   3942   (let ((line (flycheck-error-line err))
   3943         (column (flycheck-error-column err))
   3944         (end-line (flycheck-error-end-line err))
   3945         (end-column (flycheck-error-end-column err)))
   3946     (if (and line column)
   3947         (if (or (null end-line) (equal line end-line))
   3948             (if (or (null end-column) (equal column (1- end-column)))
   3949                 (format "%d:%d" line column)
   3950               (format "%d:%d-%d" line column end-column))
   3951           (format "(%d:%d)-(%d:%d)" line column end-line end-column))
   3952       (if (or (null end-line) (equal line end-line))
   3953           (format "%d" line)
   3954         (format "%d-%d" line end-line)))))
   3955 
   3956 (defun flycheck-error-format (err &optional with-file-name)
   3957   "Format ERR as human-readable string, optionally WITH-FILE-NAME.
   3958 
   3959 Return a string that represents the given ERR.  If WITH-FILE-NAME
   3960 is given and non-nil, include the file-name as well, otherwise
   3961 omit it."
   3962   (let* ((level (symbol-name (flycheck-error-level err)))
   3963          (checker (symbol-name (flycheck-error-checker err)))
   3964          (format `(,@(when with-file-name
   3965                        (list (flycheck-error-filename err) ":"))
   3966                    ,(flycheck-error-format-position err) ":"
   3967                    ,level ": "
   3968                    ,(flycheck-error-format-message-and-id err)
   3969                    " (" ,checker ")")))
   3970     (apply #'concat format)))
   3971 
   3972 (defun flycheck-error-< (err1 err2)
   3973   "Determine whether ERR1 is less than ERR2 by location."
   3974   (let ((l1 (flycheck-error-line err1))
   3975         (l2 (flycheck-error-line err2)))
   3976     (if (/= l1 l2)
   3977         (< l1 l2)
   3978       (let ((c1 (or (flycheck-error-column err1) 1))
   3979             (c2 (or (flycheck-error-column err2) 1)))
   3980         (if (/= c1 c2)
   3981             (< c1 c2)
   3982           (let ((el1 (or (flycheck-error-end-line err1) l1))
   3983                 (el2 (or (flycheck-error-end-line err2) l2)))
   3984             (if (/= el1 el2)
   3985                 (< el1 el2)
   3986               (let ((cl1 (or (flycheck-error-end-column err1) 1))
   3987                     (cl2 (or (flycheck-error-end-column err2) 1)))
   3988                 (< cl1 cl2)))))))))
   3989 
   3990 (defun flycheck-error-level-< (err1 err2)
   3991   "Determine whether ERR1 is less than ERR2 by error level.
   3992 
   3993 Like `flycheck-error-<', but compares by error level severity
   3994 first.  Levels of the same severity are compared by name."
   3995   (let* ((level1 (flycheck-error-level err1))
   3996          (level2 (flycheck-error-level err2))
   3997          (severity1 (flycheck-error-level-severity level1))
   3998          (severity2 (flycheck-error-level-severity level2)))
   3999     (cond
   4000      ((= severity1 severity2)
   4001       (if (string= level1 level2)
   4002           (flycheck-error-< err1 err2)
   4003         (string< level1 level2)))
   4004      (t (< severity1 severity2)))))
   4005 
   4006 (defun flycheck-assert-error-list-p (errors)
   4007   "Assert that all items in ERRORS are of `flycheck-error' type.
   4008 
   4009 Signal an error if any item in ERRORS is not a `flycheck-error'
   4010 object, as by `flycheck-error-p'.  Otherwise return ERRORS
   4011 again."
   4012   (unless (listp errors)
   4013     (signal 'wrong-type-argument (list 'listp errors)))
   4014   (dolist (err errors)
   4015     (unless (flycheck-error-p err)
   4016       (signal 'wrong-type-argument (list 'flycheck-error-p err))))
   4017   errors)
   4018 
   4019 
   4020 ;;; Errors in the current buffer
   4021 (defvar-local flycheck-current-errors nil
   4022   "A list of all errors and warnings in the current buffer.")
   4023 
   4024 (defun flycheck-report-current-errors (errors)
   4025   "Report ERRORS in the current buffer.
   4026 
   4027 Add ERRORS to `flycheck-current-errors' and process each error
   4028 with `flycheck-process-error-functions'."
   4029   (setq flycheck-current-errors (append errors flycheck-current-errors))
   4030   (overlay-recenter (point-max))
   4031   ;; We can't use `seq-sort-by' because it's not in Emacs 25's built-in `seq',
   4032   ;; and installing an updated version doesn't help (this is a package.el bug;
   4033   ;; see https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg01974.html).
   4034   (seq-do (lambda (err)
   4035             (run-hook-with-args-until-success 'flycheck-process-error-functions
   4036                                               err))
   4037           (seq-sort (lambda (e1 e2)
   4038                       (< (flycheck-error-line e1) (flycheck-error-line e2)))
   4039                     errors)))
   4040 
   4041 (defun flycheck-clear-errors ()
   4042   "Remove all error information from the current buffer."
   4043   (setq flycheck-current-errors nil)
   4044   (flycheck-report-status 'not-checked))
   4045 
   4046 (defun flycheck-fill-and-expand-error-file-names (errors directory)
   4047   "Fill and expand file names in ERRORS relative to DIRECTORY.
   4048 
   4049 Expand all file names of ERRORS against DIRECTORY.  If the file
   4050 name of an error is nil fill in the result of function
   4051 `buffer-file-name' in the current buffer.
   4052 
   4053 Return ERRORS, modified in-place."
   4054   (seq-do (lambda (err)
   4055             (setf (flycheck-error-filename err)
   4056                   (if-let (filename (flycheck-error-filename err))
   4057                       (expand-file-name filename directory)
   4058                     (buffer-file-name))))
   4059           errors)
   4060   errors)
   4061 
   4062 (defun flycheck-relevant-error-other-file-p (err)
   4063   "Determine whether ERR is a relevant error for another file."
   4064   (let ((file-name (flycheck-error-filename err)))
   4065     (and file-name
   4066          flycheck-relevant-error-other-file-show
   4067          (or (null buffer-file-name)
   4068              (not (flycheck-same-files-p buffer-file-name file-name)))
   4069          (<= (flycheck-error-level-severity
   4070               flycheck-relevant-error-other-file-minimum-level)
   4071              (flycheck-error-level-severity (flycheck-error-level err))))))
   4072 
   4073 (defun flycheck-relevant-error-p (err)
   4074   "Determine whether ERR is relevant for the current buffer.
   4075 
   4076 Return t if ERR may be shown for the current buffer, or nil
   4077 otherwise."
   4078   (flycheck-error-with-buffer err
   4079     (let ((file-name (flycheck-error-filename err))
   4080           (message (flycheck-error-message err)))
   4081       (and
   4082        (or
   4083         ;; Neither the error nor buffer have a file name
   4084         (and (not file-name) (not buffer-file-name))
   4085         ;; Both have files, and they match
   4086         (and buffer-file-name file-name
   4087              (flycheck-same-files-p file-name buffer-file-name))
   4088         ;; This is a significant error from another file
   4089         (flycheck-relevant-error-other-file-p err))
   4090        message
   4091        (not (string-empty-p message))
   4092        ;; Errors without line numbers are discarded.  If a linter
   4093        ;; reports relevant errors without line numbers, use
   4094        ;; `flycheck-fill-empty-line-numbers' as the checker's
   4095        ;; `:error-filter' to set them to line 0.
   4096        (flycheck-error-line err)))))
   4097 
   4098 (defun flycheck-relevant-errors (errors)
   4099   "Filter the relevant errors from ERRORS.
   4100 
   4101 Return a list of all errors that are relevant for their
   4102 corresponding buffer."
   4103   (seq-filter #'flycheck-relevant-error-p errors))
   4104 
   4105 (defun flycheck-related-errors (err &optional error-set)
   4106   "Get all the errors that are in the same group as ERR.
   4107 
   4108 Return a list of all errors (from ERROR-SET) that have the same
   4109 `flycheck-error-group' as ERR, including ERR itself.
   4110 
   4111 If ERROR-SET is nil, `flycheck-current-errors' is used instead."
   4112   (let ((group (flycheck-error-group err))
   4113         (checker (flycheck-error-checker err)))
   4114     (if group
   4115         (seq-filter (lambda (e)
   4116                       (and (eq (flycheck-error-checker e) checker)
   4117                            (eq (flycheck-error-group e) group)))
   4118                     (or error-set flycheck-current-errors))
   4119       (list err))))
   4120 
   4121 
   4122 ;;; Status reporting for the current buffer
   4123 (defvar-local flycheck-last-status-change 'not-checked
   4124   "The last status change in the current buffer.")
   4125 
   4126 (defun flycheck-report-failed-syntax-check (&optional status)
   4127   "Report a failed Flycheck syntax check with STATUS.
   4128 
   4129 STATUS is a status symbol for `flycheck-report-status',
   4130 defaulting to `errored'.
   4131 
   4132 Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and
   4133 report an error STATUS."
   4134   (flycheck-clear)
   4135   (setq flycheck-current-syntax-check nil)
   4136   (run-hooks 'flycheck-syntax-check-failed-hook)
   4137   (flycheck-report-status (or status 'errored)))
   4138 
   4139 (defun flycheck-report-status (status)
   4140   "Report Flycheck STATUS.
   4141 
   4142 STATUS is one of the following symbols:
   4143 
   4144 `not-checked'
   4145      The current buffer was not checked.
   4146 
   4147 `no-checker'
   4148      Automatic syntax checker selection did not find a suitable
   4149      syntax checker.
   4150 
   4151 `running'
   4152      A syntax check is now running in the current buffer.
   4153 
   4154 `errored'
   4155      The current syntax check has errored.
   4156 
   4157 `finished'
   4158      The current syntax check was finished normally.
   4159 
   4160 `interrupted'
   4161      The current syntax check was interrupted.
   4162 
   4163 `suspicious'
   4164      The last syntax check had a suspicious result.
   4165 
   4166 Set `flycheck-last-status-change' and call
   4167 `flycheck-status-changed-functions' with STATUS.  Afterwards
   4168 refresh the mode line."
   4169   (setq flycheck-last-status-change status)
   4170   (run-hook-with-args 'flycheck-status-changed-functions status)
   4171   (force-mode-line-update))
   4172 
   4173 (defun flycheck-mode-line-status-text (&optional status)
   4174   "Get a text describing STATUS for use in the mode line.
   4175 
   4176 STATUS defaults to `flycheck-last-status-change' if omitted or
   4177 nil."
   4178   (let* ((current-status (or status flycheck-last-status-change))
   4179          (indicator (pcase current-status
   4180                       (`not-checked "")
   4181                       (`no-checker "-")
   4182                       (`running "*")
   4183                       (`errored "!")
   4184                       (`finished
   4185                        (let-alist (flycheck-count-errors flycheck-current-errors)
   4186                          (if (or .error .warning)
   4187                              (format ":%s|%s" (or .error 0) (or .warning 0))
   4188                            flycheck-mode-success-indicator)))
   4189                       (`interrupted ".")
   4190                       (`suspicious "?")))
   4191          (face (when flycheck-mode-line-color
   4192                  (pcase current-status
   4193                    (`errored 'error)
   4194                    (`finished
   4195                     (let-alist (flycheck-count-errors flycheck-current-errors)
   4196                       (if (or .error .warning) 'error 'success))))))
   4197          (text (format " %s%s" flycheck-mode-line-prefix indicator)))
   4198     (when face
   4199       (setq text (propertize text 'face face)))
   4200     text))
   4201 
   4202 
   4203 ;;; Error levels
   4204 (defun flycheck-make-margin-spec (margin-str face)
   4205   "Make a display spec to indicate errors in the margins.
   4206 
   4207 Returns MARGIN-STR with FACE applied."
   4208   (propertize margin-str 'face `(,face default)))
   4209 
   4210 (defconst flycheck-default-margin-str "»"
   4211   "String used to indicate errors in the margins.")
   4212 
   4213 (defconst flycheck-default-margin-continuation-str "⋮"
   4214   "String used to indicate continuation lines in the margins.")
   4215 
   4216 ;;;###autoload
   4217 (defun flycheck-define-error-level (level &rest properties)
   4218   "Define a new error LEVEL with PROPERTIES.
   4219 
   4220 The following PROPERTIES constitute an error level:
   4221 
   4222 `:severity SEVERITY'
   4223      A number denoting the severity of this level.  The higher
   4224      the number, the more severe is this level compared to other
   4225      levels.  Defaults to 0; info is -10, warning is 10, and
   4226      error is 100.
   4227 
   4228      The severity is used by `flycheck-error-level-<' to
   4229      determine the ordering of errors according to their levels.
   4230 
   4231 `:compilation-level LEVEL'
   4232 
   4233      A number indicating the broad class of messages that errors
   4234      at this level belong to: one of 0 (info), 1 (warning), or
   4235      2 or nil (error).  Defaults to nil.
   4236 
   4237      This is used by `flycheck-checker-pattern-to-error-regexp'
   4238      to map error levels into `compilation-mode''s hierarchy and
   4239      to get proper highlighting of errors in `compilation-mode'.
   4240 
   4241 `:overlay-category CATEGORY'
   4242      A symbol denoting the overlay category to use for error
   4243      highlight overlays for this level.  See Info
   4244      node `(elisp)Overlay Properties' for more information about
   4245      overlay categories.
   4246 
   4247      A category for an error level overlay should at least define
   4248      the `face' property, for error highlighting.  Another useful
   4249      property for error level categories is `priority', to
   4250      influence the stacking of multiple error level overlays.
   4251 
   4252 `:fringe-bitmap BITMAPS'
   4253      A fringe bitmap symbol denoting the bitmap to use for fringe
   4254      indicators for this level, or a cons of two bitmaps (one for
   4255      narrow fringes and one for wide fringes).  See Info node
   4256      `(elisp)Fringe Bitmaps' for more information about fringe
   4257      bitmaps, including a list of built-in fringe bitmaps.
   4258 
   4259 `:fringe-face FACE'
   4260      A face symbol denoting the face to use for fringe indicators
   4261      for this level.
   4262 
   4263 `:margin-spec SPEC'
   4264      A display specification indicating what to display in the
   4265      margin when `flycheck-indication-mode' is `left-margin' or
   4266      `right-margin'.  See Info node `(elisp)Displaying in the
   4267      Margins'.  If omitted, Flycheck generates an image spec from
   4268      the fringe bitmap.
   4269 
   4270 `:error-list-face FACE'
   4271      A face symbol denoting the face to use for messages of this
   4272      level in the error list.  See `flycheck-list-errors'."
   4273   (declare (indent 1))
   4274   (setf (get level 'flycheck-error-level) t)
   4275   (setf (get level 'flycheck-error-severity)
   4276         (or (plist-get properties :severity) 0))
   4277   (setf (get level 'flycheck-compilation-level)
   4278         (plist-get properties :compilation-level))
   4279   (setf (get level 'flycheck-overlay-category)
   4280         (plist-get properties :overlay-category))
   4281   (setf (get level 'flycheck-fringe-bitmaps)
   4282         (let ((bitmap (plist-get properties :fringe-bitmap)))
   4283           (if (consp bitmap) bitmap (cons bitmap bitmap))))
   4284   ;; Kept for compatibility
   4285   (setf (get level 'flycheck-fringe-bitmap-double-arrow)
   4286         (car (get level 'flycheck-fringe-bitmaps)))
   4287   (setf (get level 'flycheck-fringe-face)
   4288         (plist-get properties :fringe-face))
   4289   (setf (get level 'flycheck-margin-spec)
   4290         (or (plist-get properties :margin-spec)
   4291             (flycheck-make-margin-spec
   4292              flycheck-default-margin-str
   4293              (or (get level 'flycheck-fringe-face) 'default))))
   4294   (setf (get level 'flycheck-margin-continuation)
   4295         (flycheck-make-margin-spec
   4296          flycheck-default-margin-continuation-str
   4297          (or (get level 'flycheck-fringe-face) 'default)))
   4298   (setf (get level 'flycheck-error-list-face)
   4299         (plist-get properties :error-list-face)))
   4300 
   4301 (defun flycheck-error-level-p (level)
   4302   "Determine whether LEVEL is a Flycheck error level."
   4303   (get level 'flycheck-error-level))
   4304 
   4305 (defun flycheck-error-level-severity (level)
   4306   "Get the numeric severity of LEVEL."
   4307   (or (get level 'flycheck-error-severity) 0))
   4308 
   4309 (defun flycheck-error-level-compilation-level (level)
   4310   "Get the compilation level for LEVEL."
   4311   (get level 'flycheck-compilation-level))
   4312 
   4313 (defun flycheck-error-level-overlay-category (level)
   4314   "Get the overlay category for LEVEL."
   4315   (get level 'flycheck-overlay-category))
   4316 
   4317 (defun flycheck-error-level-margin-spec (level)
   4318   "Get the margin spec for LEVEL."
   4319   (get level 'flycheck-margin-spec))
   4320 
   4321 (defun flycheck-error-level-margin-continuation-spec (level)
   4322   "Get the margin continuation spec for LEVEL."
   4323   (get level 'flycheck-margin-continuation))
   4324 
   4325 (defun flycheck-error-level-fringe-bitmap (level &optional hi-res)
   4326   "Get the fringe bitmap for LEVEL.
   4327 
   4328 Optional argument HI-RES non-nil means that the returned bitmap
   4329 will be the high resolution version."
   4330   (let ((bitmaps (get level 'flycheck-fringe-bitmaps)))
   4331     (if hi-res (cdr bitmaps) (car bitmaps))))
   4332 
   4333 (defun flycheck-error-level-fringe-face (level)
   4334   "Get the fringe face for LEVEL."
   4335   (get level 'flycheck-fringe-face))
   4336 
   4337 (defun flycheck-error-level-error-list-face (level)
   4338   "Get the error list face for LEVEL."
   4339   (get level 'flycheck-error-list-face))
   4340 
   4341 (defun flycheck-error-level-make-indicator (level side &optional continuation)
   4342   "Create the fringe or margin icon for LEVEL at SIDE.
   4343 
   4344 Return a propertized string that shows an indicator according
   4345 to LEVEL and the given fringe or margin SIDE.
   4346 
   4347 LEVEL is a Flycheck error level defined with
   4348 `flycheck-define-error-level', and SIDE is either `left-fringe',
   4349 `right-fringe', `left-margin', or `right-margin'.
   4350 
   4351 CONTINUATION indicates which fringe bitmap or margin spec to use:
   4352 either the `:fringe-bitmap' and `:margin-spec' properties of
   4353 LEVEL when CONTINUATION is nil or omitted, or bitmaps and specs
   4354 indicating an error spanning more than one line.
   4355 
   4356 Return a propertized string representing the fringe icon,
   4357 intended for use as `before-string' of an overlay to actually
   4358 show the indicator."
   4359   (propertize
   4360    "!" 'display
   4361    (pcase side
   4362      ((or `left-fringe `right-fringe)
   4363       (list side
   4364             (if continuation 'flycheck-fringe-bitmap-continuation
   4365               (let* ((fringe-width
   4366                       (pcase side
   4367                         (`left-fringe (car (window-fringes)))
   4368                         (`right-fringe (cadr (window-fringes)))))
   4369                      (high-res (>= fringe-width 16)))
   4370                 (flycheck-error-level-fringe-bitmap level high-res)))
   4371             (flycheck-error-level-fringe-face level)))
   4372      ((or `left-margin `right-margin)
   4373       `((margin ,side)
   4374         ,(or (if continuation
   4375                  (flycheck-error-level-margin-continuation-spec level)
   4376                (flycheck-error-level-margin-spec level))
   4377              "")))
   4378      (_ (error "Invalid fringe side: %S" side)))))
   4379 
   4380 (define-obsolete-function-alias
   4381   'flycheck-error-level-make-fringe-icon
   4382   'flycheck-error-level-make-indicator
   4383   "33")
   4384 
   4385 
   4386 ;;; Built-in error levels
   4387 (defconst flycheck-fringe-bitmap-double-arrow
   4388   [#b11011000
   4389    #b01101100
   4390    #b00110110
   4391    #b00011011
   4392    #b00110110
   4393    #b01101100
   4394    #b11011000]
   4395   "Bitmaps used to indicate errors in the left fringes.")
   4396 
   4397 (defconst flycheck-fringe-bitmap-double-left-arrow
   4398   [#b00011011
   4399    #b00110110
   4400    #b01101100
   4401    #b11011000
   4402    #b01101100
   4403    #b00110110
   4404    #b00011011]
   4405   "Bitmaps used to indicate errors in the right fringes.")
   4406 
   4407 (defconst flycheck-fringe-bitmap-double-arrow-hi-res
   4408   [#b1111001111000000
   4409    #b0111100111100000
   4410    #b0011110011110000
   4411    #b0001111001111000
   4412    #b0000111100111100
   4413    #b0000011110011110
   4414    #b0000011110011110
   4415    #b0000111100111100
   4416    #b0001111001111000
   4417    #b0011110011110000
   4418    #b0111100111100000
   4419    #b1111001111000000]
   4420   "High-resolution bitmap used to indicate errors in the left fringes.")
   4421 
   4422 (defconst flycheck-fringe-bitmap-double-left-arrow-hi-res
   4423   [#b0000001111001111
   4424    #b0000011110011110
   4425    #b0000111100111100
   4426    #b0001111001111000
   4427    #b0011110011110000
   4428    #b0111100111100000
   4429    #b0111100111100000
   4430    #b0011110011110000
   4431    #b0001111001111000
   4432    #b0000111100111100
   4433    #b0000011110011110
   4434    #b0000001111001111]
   4435   "High-resolution bitmap used to indicate errors in the right fringes.")
   4436 
   4437 (defconst flycheck-fringe-bitmap-continuation
   4438   [#b1000000010000000
   4439    #b0010000000100000
   4440    #b0000100000001000
   4441    #b0000001000000010]
   4442   "Bitmap used to indicate continuation lines in the fringes.")
   4443 
   4444 (when (fboundp 'define-fringe-bitmap) ;; #ifdef HAVE_WINDOW_SYSTEM
   4445   (define-fringe-bitmap
   4446     'flycheck-fringe-bitmap-double-arrow
   4447     flycheck-fringe-bitmap-double-arrow)
   4448   (define-fringe-bitmap
   4449     'flycheck-fringe-bitmap-double-arrow-hi-res
   4450     flycheck-fringe-bitmap-double-arrow-hi-res
   4451     nil 16)
   4452   (define-fringe-bitmap
   4453     'flycheck-fringe-bitmap-double-left-arrow
   4454     flycheck-fringe-bitmap-double-left-arrow)
   4455   (define-fringe-bitmap
   4456     'flycheck-fringe-bitmap-double-left-arrow-hi-res
   4457     flycheck-fringe-bitmap-double-left-arrow-hi-res
   4458     nil 16)
   4459   (define-fringe-bitmap
   4460     'flycheck-fringe-bitmap-continuation
   4461     flycheck-fringe-bitmap-continuation
   4462     nil 16 '(top repeat)))
   4463 
   4464 (defun flycheck-redefine-standard-error-levels
   4465     (&optional margin-str fringe-bitmap)
   4466   "Redefine Flycheck's standard error levels.
   4467 
   4468 This is useful to change the character drawn in the
   4469 margins (MARGIN-STR, a string) or the bitmap drawn in the
   4470 fringes (FRINGE-BITMAP, a fringe bitmap symbol or a cons of such
   4471 symbols, as in `flycheck-define-error-level')."
   4472   (unless margin-str
   4473     (setq margin-str flycheck-default-margin-str))
   4474 
   4475   (unless fringe-bitmap
   4476     (setq fringe-bitmap
   4477           (cons 'flycheck-fringe-bitmap-double-arrow
   4478                 'flycheck-fringe-bitmap-double-arrow-hi-res)))
   4479 
   4480   (setf (get 'flycheck-error-overlay 'face) 'flycheck-error)
   4481   (setf (get 'flycheck-error-overlay 'priority) 110)
   4482 
   4483   (flycheck-define-error-level 'error
   4484     :severity 100
   4485     :compilation-level 2
   4486     :overlay-category 'flycheck-error-overlay
   4487     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-error)
   4488     :fringe-bitmap fringe-bitmap
   4489     :fringe-face 'flycheck-fringe-error
   4490     :error-list-face 'flycheck-error-list-error)
   4491 
   4492   (setf (get 'flycheck-warning-overlay 'face) 'flycheck-warning)
   4493   (setf (get 'flycheck-warning-overlay 'priority) 100)
   4494 
   4495   (flycheck-define-error-level 'warning
   4496     :severity 10
   4497     :compilation-level 1
   4498     :overlay-category 'flycheck-warning-overlay
   4499     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-warning)
   4500     :fringe-bitmap fringe-bitmap
   4501     :fringe-face 'flycheck-fringe-warning
   4502     :error-list-face 'flycheck-error-list-warning)
   4503 
   4504   (setf (get 'flycheck-info-overlay 'face) 'flycheck-info)
   4505   (setf (get 'flycheck-info-overlay 'priority) 90)
   4506 
   4507   (flycheck-define-error-level 'info
   4508     :severity -10
   4509     :compilation-level 0
   4510     :overlay-category 'flycheck-info-overlay
   4511     :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-info)
   4512     :fringe-bitmap fringe-bitmap
   4513     :fringe-face 'flycheck-fringe-info
   4514     :error-list-face 'flycheck-error-list-info))
   4515 
   4516 (flycheck-redefine-standard-error-levels)
   4517 
   4518 
   4519 ;;; Error filtering
   4520 (defun flycheck-filter-errors (errors checker)
   4521   "Filter ERRORS from CHECKER.
   4522 
   4523 Apply the error filter of CHECKER to ERRORs and return the
   4524 result.  If CHECKER has no error filter, fall back to
   4525 `flycheck-sanitize-errors'."
   4526   (let ((filter (or (flycheck-checker-get checker 'error-filter)
   4527                     #'flycheck-sanitize-errors)))
   4528     (funcall filter errors)))
   4529 
   4530 (defun flycheck-sanitize-errors (errors)
   4531   "Sanitize ERRORS.
   4532 
   4533 Sanitize ERRORS by trimming leading and trailing whitespace in
   4534 all error messages, and by replacing 0 columns and empty error
   4535 messages with nil.
   4536 
   4537 Returns sanitized ERRORS."
   4538   (dolist (err errors)
   4539     (flycheck-error-with-buffer err
   4540       (let ((message (flycheck-error-message err))
   4541             (id (flycheck-error-id err)))
   4542         (when message
   4543           (setq message (string-trim message))
   4544           (setf (flycheck-error-message err)
   4545                 (if (string-empty-p message) nil message)))
   4546         (when (and id (string-empty-p id))
   4547           (setf (flycheck-error-id err) nil))
   4548         (when (eq (flycheck-error-column err) 0)
   4549           (setf (flycheck-error-column err) nil))
   4550         (when (eq (flycheck-error-end-column err) 0)
   4551           (setf (flycheck-error-end-column err) nil)))))
   4552   errors)
   4553 
   4554 (defun flycheck-remove-error-file-names (file-name errors)
   4555   "Remove matching FILE-NAME from ERRORS.
   4556 
   4557 Use as `:error-filter' for syntax checkers that output faulty
   4558 filenames.  Flycheck will later fill in the buffer file name.
   4559 
   4560 Return ERRORS."
   4561   (seq-do (lambda (err)
   4562             (when (and (flycheck-error-filename err)
   4563                        (string= (flycheck-error-filename err) file-name))
   4564               (setf (flycheck-error-filename err) nil)))
   4565           errors)
   4566   errors)
   4567 
   4568 (defun flycheck-increment-error-columns (errors &optional offset)
   4569   "Increment all columns of ERRORS by OFFSET (default: 1).
   4570 
   4571   Use this as `:error-filter' if a syntax checker outputs 0-based
   4572   columns."
   4573   (setq offset (or offset 1)) ;; Emacs bug #31715
   4574   (seq-do (lambda (err)
   4575             (when (flycheck-error-column err)
   4576               (cl-incf (flycheck-error-column err) offset))
   4577             (when (flycheck-error-end-column err)
   4578               (cl-incf (flycheck-error-end-column err) offset)))
   4579           errors)
   4580   errors)
   4581 
   4582 (defun flycheck-collapse-error-message-whitespace (errors)
   4583   "Collapse whitespace in all messages of ERRORS.
   4584 
   4585 Return ERRORS."
   4586   (dolist (err errors)
   4587     (when-let (message (flycheck-error-message err))
   4588       (setf (flycheck-error-message err)
   4589             (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r")))
   4590                                       " " message 'fixed-case 'literal))))
   4591   errors)
   4592 
   4593 (defun flycheck-dedent-error-messages (errors)
   4594   "Dedent all messages of ERRORS.
   4595 
   4596 For each error in ERRORS, determine the indentation offset from
   4597 the leading whitespace of the first line, and dedent all further
   4598 lines accordingly.
   4599 
   4600 Return ERRORS, with in-place modifications."
   4601   (dolist (err errors)
   4602     (when-let (message (flycheck-error-message err))
   4603       (with-temp-buffer
   4604         (insert message)
   4605         ;; Determine the indentation offset
   4606         (goto-char (point-min))
   4607         (back-to-indentation)
   4608         (let* ((indent-offset (- (point) (point-min))))
   4609           ;; Now iterate over all lines and dedent each according to
   4610           ;; `indent-offset'
   4611           (while (not (eobp))
   4612             (back-to-indentation)
   4613             ;; If the current line starts with sufficient whitespace, delete the
   4614             ;; indentation offset.  Otherwise keep the line intact, as we might
   4615             ;; loose valuable information
   4616             (when (>= (- (point) (line-beginning-position)) indent-offset)
   4617               (delete-char (- indent-offset)))
   4618             (forward-line 1)))
   4619         (delete-trailing-whitespace (point-min) (point-max))
   4620         (setf (flycheck-error-message err)
   4621               (buffer-substring-no-properties (point-min) (point-max))))))
   4622   errors)
   4623 
   4624 (defun flycheck-fold-include-levels (errors sentinel-message)
   4625   "Fold levels of ERRORS from included files.
   4626 
   4627 ERRORS is a list of `flycheck-error' objects.  SENTINEL-MESSAGE
   4628 is a regular expression matched against the error message to
   4629 determine whether the error denotes errors from an included
   4630 file.  Alternatively, it is a function that is given an error and
   4631 shall return non-nil, if the error denotes errors from an
   4632 included file."
   4633   (unless (or (stringp sentinel-message) (functionp sentinel-message))
   4634     (error "Sentinel must be string or function: %S" sentinel-message))
   4635   (let ((sentinel (if (functionp sentinel-message)
   4636                       sentinel-message
   4637                     (lambda (err)
   4638                       (string-match-p sentinel-message
   4639                                       (flycheck-error-message err)))))
   4640         (remaining-errors errors))
   4641     (while remaining-errors
   4642       (let* ((current-error (pop remaining-errors)))
   4643         (when (funcall sentinel current-error)
   4644           ;; We found an error denoting errors in the included file:
   4645           ;; 1. process all subsequent errors until faulty include file is found
   4646           ;; 2. process again all subsequent errors until an error has the
   4647           ;;    current file name again
   4648           ;; 3. find the most severe error level
   4649           (let ((current-filename (flycheck-error-filename current-error))
   4650                 (current-level nil)
   4651                 (faulty-include-filename nil)
   4652                 (filename nil)
   4653                 (done (null remaining-errors)))
   4654 
   4655             (while (not done)
   4656               (setq filename (flycheck-error-filename (car remaining-errors)))
   4657               (unless faulty-include-filename
   4658                 (unless (string= filename current-filename)
   4659                   (setq faulty-include-filename filename)))
   4660 
   4661               (let* ((error-in-include (pop remaining-errors))
   4662                      (in-include-level (flycheck-error-level error-in-include)))
   4663                 (unless (funcall sentinel error-in-include)
   4664                   ;; Ignore nested "included file" errors, we are only
   4665                   ;; interested in real errors because these define our level
   4666                   (when (or (not current-level)
   4667                             (> (flycheck-error-level-severity in-include-level)
   4668                                (flycheck-error-level-severity current-level)))
   4669                     (setq current-level in-include-level))))
   4670 
   4671               (setq done (or (null remaining-errors)
   4672                              (and faulty-include-filename
   4673                                   (string= filename current-filename)))))
   4674 
   4675             (setf (flycheck-error-level current-error) current-level
   4676                   (flycheck-error-message current-error)
   4677                   (format "In include %s" faulty-include-filename))))))
   4678     errors))
   4679 
   4680 (defun flycheck-dequalify-error-ids (errors)
   4681   "De-qualify error ids in ERRORS.
   4682 
   4683 Remove all qualifications from error ids in ERRORS, by stripping
   4684 all leading dotted components from error IDs.  For instance, if
   4685 the error ID is com.foo.E100, replace it with E100.
   4686 
   4687 This error filter is mainly useful to simplify error IDs obtained
   4688 from parsing Checkstyle XML, which frequently has very verbose
   4689 IDs, that include the name of the tool."
   4690   (seq-do (lambda (err)
   4691             (let ((id (flycheck-error-id err)))
   4692               (when id
   4693                 (setf (flycheck-error-id err)
   4694                       (replace-regexp-in-string
   4695                        (rx string-start
   4696                            (group
   4697                             (optional (zero-or-more not-newline) "."))
   4698                            (one-or-more (not (any ".")))
   4699                            string-end)
   4700                        "" id 'fixedcase 'literal 1)))))
   4701           errors)
   4702   errors)
   4703 
   4704 (defun flycheck-remove-error-ids (errors)
   4705   "Remove all error ids from ERRORS."
   4706   (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors)
   4707   errors)
   4708 
   4709 (defun flycheck-fill-empty-line-numbers (errors)
   4710   "Set ERRORS without lines to line 0.
   4711 
   4712 Use as `:error-filter' for syntax checkers that output errors
   4713 without line numbers.
   4714 
   4715 Return ERRORS."
   4716   (seq-do (lambda (err)
   4717             (unless (flycheck-error-line err)
   4718               (setf (flycheck-error-line err) 0)))
   4719           errors)
   4720   errors)
   4721 
   4722 
   4723 ;;; Error analysis
   4724 (defun flycheck-count-errors (errors)
   4725   "Count the number of ERRORS, grouped by level.
   4726 
   4727 Return an alist, where each ITEM is a cons cell whose `car' is an
   4728 error level, and whose `cdr' is the number of errors of that
   4729 level."
   4730   (let (counts-by-level)
   4731     (dolist (err errors)
   4732       (let* ((level (flycheck-error-level err))
   4733              (item (assq level counts-by-level)))
   4734         (if item
   4735             (cl-incf (cdr item))
   4736           (push (cons level 1) counts-by-level))))
   4737     counts-by-level))
   4738 
   4739 (defun flycheck-has-max-errors-p (errors level)
   4740   "Check if there is no error in ERRORS more severe than LEVEL."
   4741   (let ((severity (flycheck-error-level-severity level)))
   4742     (seq-every-p (lambda (e) (<= (flycheck-error-level-severity
   4743                                   (flycheck-error-level e))
   4744                                  severity))
   4745                  errors)))
   4746 
   4747 (defun flycheck-has-max-current-errors-p (level)
   4748   "Check if there is no current error more severe than LEVEL."
   4749   (flycheck-has-max-errors-p flycheck-current-errors level))
   4750 
   4751 (defun flycheck-has-errors-p (errors level)
   4752   "Determine if there are any ERRORS with LEVEL."
   4753   (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors))
   4754 
   4755 (defun flycheck-has-current-errors-p (&optional level)
   4756   "Determine if the current buffer has errors with LEVEL.
   4757 
   4758 If LEVEL is omitted if the current buffer has any errors at all."
   4759   (if level
   4760       (flycheck-has-errors-p flycheck-current-errors level)
   4761     (and flycheck-current-errors t)))
   4762 
   4763 
   4764 ;;; Error overlays in the current buffer
   4765 (defvar-local flycheck--last-overlay-index 0
   4766   "Last index given to a Flycheck overlay.
   4767 
   4768 These indices are used to preserve error order (Emacs doesn't
   4769 preserve overlay order when calling `overlays-at').")
   4770 
   4771 (defun flycheck--next-overlay-index ()
   4772   "Compute the index to assign to a new Flycheck overlay."
   4773   (cl-incf flycheck--last-overlay-index))
   4774 
   4775 (defun flycheck--highlighting-style (err)
   4776   "Determine the highlighting style to apply to ERR.
   4777 
   4778 Styles are documented in `flycheck-highlighting-style'; this
   4779 functions resolves `conditional' style specifications."
   4780   (let* ((style flycheck-highlighting-style)
   4781          (first-line (flycheck-error-line err))
   4782          (end-line (or (flycheck-error-end-line err) first-line))
   4783          (nlines (- end-line first-line)))
   4784     (while (eq (car-safe style) 'conditional)
   4785       (pcase-let ((`(,threshold ,s1 ,s2) (cdr style)))
   4786         (setq style (if (< nlines threshold) s1 s2))))
   4787     (pcase style
   4788       (`(delimiters ,before ,after)
   4789        (when (characterp before)
   4790          (setq before (flycheck--make-highlighting-delimiter before)))
   4791        (when (characterp after)
   4792          (setq after (flycheck--make-highlighting-delimiter after)))
   4793        (setq style `(delimiters ,before ,after))))
   4794     style))
   4795 
   4796 (defun flycheck--setup-highlighting (err overlay)
   4797   "Apply properties to OVERLAY to highlight ERR."
   4798   (let ((level (flycheck-error-level err)))
   4799     (unless flycheck-highlighting-mode
   4800       ;; Erase the highlighting from the overlay if requested by the user
   4801       (setf (overlay-get overlay 'face) nil))
   4802     (when flycheck-indication-mode
   4803       (setf (overlay-get overlay 'before-string)
   4804             (flycheck-error-level-make-indicator
   4805              level flycheck-indication-mode))
   4806       (setf (overlay-get overlay 'line-prefix)
   4807             (flycheck-error-level-make-indicator
   4808              level flycheck-indication-mode t)))
   4809     (pcase (flycheck--highlighting-style err)
   4810       ((or `nil (guard (null flycheck-highlighting-mode)))
   4811        ;; Erase the highlighting
   4812        (setf (overlay-get overlay 'face) nil))
   4813       (`level-face)
   4814       (`(delimiters ,before ,after)
   4815        ;; Replace the highlighting with delimiters
   4816        (let* ((fringe-face (flycheck-error-level-fringe-face level))
   4817               (delim-face `(flycheck-error-delimiter ,fringe-face)))
   4818          (setf (overlay-get overlay 'face) 'flycheck-delimited-error)
   4819          (setf (overlay-get overlay 'before-string)
   4820                (concat (propertize before 'face delim-face)
   4821                        (or (overlay-get overlay 'before-string) "")))
   4822          (setf (overlay-get overlay 'after-string)
   4823                (propertize after 'face delim-face))))
   4824       (other (error "Unsupported highlighting style: %S" other)))))
   4825 
   4826 (defun flycheck-add-overlay (err)
   4827   "Add overlay for ERR.
   4828 
   4829 Return the created overlay."
   4830   ;; We must have a proper error region for the sake of fringe indication,
   4831   ;; error display and error navigation, even if the highlighting is disabled.
   4832   ;; We erase the highlighting later on in this case
   4833   (pcase-let* ((`(,beg . ,end)
   4834                 (if (flycheck-relevant-error-other-file-p err)
   4835                     ;; Display overlays for other-file errors on the first line
   4836                     (cons (point-min)
   4837                           (save-excursion (goto-char (point-min))
   4838                                           (line-end-position)))
   4839                   (flycheck-error-region-for-mode
   4840                    err (or flycheck-highlighting-mode 'lines))))
   4841                (overlay (make-overlay beg end))
   4842                (level (flycheck-error-level err))
   4843                (category (flycheck-error-level-overlay-category level))
   4844                (index (flycheck--next-overlay-index)))
   4845     (unless (flycheck-error-level-p level)
   4846       (error "Undefined error level: %S" level))
   4847     (setf (overlay-get overlay 'flycheck-error-index) index)
   4848     (setf (overlay-get overlay 'flycheck-overlay) t)
   4849     (setf (overlay-get overlay 'flycheck-error) err)
   4850     (setf (overlay-get overlay 'category) category)
   4851     (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo)
   4852     (flycheck--setup-highlighting err overlay)
   4853     overlay))
   4854 
   4855 (defun flycheck-help-echo (_window object pos)
   4856   "Construct a tooltip message.
   4857 
   4858 Most of the actual work is done by calling
   4859 `flycheck-help-echo-function' with the appropriate list of
   4860 errors.  Arguments WINDOW, OBJECT and POS are as described in
   4861 info node `(elisp)Special properties', as this function is
   4862 intended to be used as the \\='help-echo property of flycheck error
   4863 overlays."
   4864   (when-let (buf (cond ((bufferp object) object)
   4865                        ((overlayp object) (overlay-buffer object))))
   4866     (with-current-buffer buf
   4867       (when-let* ((fn flycheck-help-echo-function)
   4868                   (errs (flycheck-overlay-errors-at pos)))
   4869         (propertize (funcall fn errs) 'help-echo-inhibit-substitution t)))))
   4870 
   4871 (defun flycheck-help-echo-all-error-messages (errs)
   4872   "Concatenate error messages and ids from ERRS."
   4873   (pcase (delq nil errs) ;; FIXME why would errors be nil here?
   4874     (`(,err) ;; A single error
   4875      (flycheck-error-format-message-and-id err))
   4876     (_ ;; Zero or multiple errors
   4877      (mapconcat
   4878       (lambda (err)
   4879         (flycheck-error-format-message-and-id err 'include-snippet))
   4880       errs "\n"))))
   4881 
   4882 (defun flycheck-filter-overlays (overlays)
   4883   "Get all Flycheck overlays from OVERLAYS, in original order."
   4884   ;; The order of errors returned from overlays is not stable, so we sort
   4885   ;; them again using the internal index to guarantee errors are always
   4886   ;; displayed in the same order.
   4887   (seq-sort
   4888    ;; We can't use `seq-sort-by' here; see above
   4889    (lambda (o1 o2) (< (overlay-get o1 'flycheck-error-index)
   4890                       (overlay-get o2 'flycheck-error-index)))
   4891    (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays)))
   4892 
   4893 (defun flycheck-overlays-at (pos)
   4894   "Get all Flycheck overlays at POS."
   4895   (flycheck-filter-overlays (overlays-at pos)))
   4896 
   4897 (defun flycheck-overlays-in (beg end)
   4898   "Get all Flycheck overlays between BEG and END."
   4899   (flycheck-filter-overlays (overlays-in beg end)))
   4900 
   4901 (defun flycheck-overlay-errors-at (pos)
   4902   "Return a list of all flycheck errors overlaid at POS."
   4903   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
   4904            (flycheck-overlays-at pos)))
   4905 
   4906 (defun flycheck-overlay-errors-in (beg end)
   4907   "Return a list of all flycheck errors overlaid between BEG and END."
   4908   (seq-map (lambda (o) (overlay-get o 'flycheck-error))
   4909            (flycheck-overlays-in beg end)))
   4910 
   4911 (defvar-local flycheck-overlays-to-delete nil
   4912   "Overlays mark for deletion after all syntax checks completed.")
   4913 (put 'flycheck-overlays-to-delete 'permanent-local t)
   4914 
   4915 (defun flycheck-delete-all-overlays ()
   4916   "Remove all flycheck overlays in the current buffer."
   4917   (overlay-recenter (point-max))
   4918   (flycheck-delete-marked-overlays)
   4919   (setq flycheck--last-overlay-index 0)
   4920   (save-restriction
   4921     (widen)
   4922     (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max)))))
   4923 
   4924 (defun flycheck-mark-all-overlays-for-deletion ()
   4925   "Mark all current overlays for deletion."
   4926   (setq flycheck-overlays-to-delete
   4927         (append (flycheck-overlays-in (point-min) (point-max))
   4928                 flycheck-overlays-to-delete)))
   4929 
   4930 (defun flycheck-delete-marked-overlays ()
   4931   "Delete all overlays marked for deletion."
   4932   (overlay-recenter (point-max))
   4933   (seq-do #'delete-overlay flycheck-overlays-to-delete)
   4934   (setq flycheck-overlays-to-delete nil))
   4935 
   4936 
   4937 ;;; Error navigation in the current buffer
   4938 (defun flycheck-error-level-interesting-at-pos-p (pos)
   4939   "Check if error severity at POS passes `flycheck-error-level-interesting-p'."
   4940   (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error)))
   4941 
   4942 (defun flycheck-error-level-interesting-p (err)
   4943   "Check if ERR severity is >= `flycheck-navigation-minimum-level'.
   4944 
   4945 ERR is also interesting (the function returns true) if there are
   4946 no errors as or more severe than `flycheck-navigation-minimum-level'."
   4947   (when (flycheck-error-p err)
   4948     (if-let (min-level flycheck-navigation-minimum-level)
   4949         (or (<= (flycheck-error-level-severity min-level)
   4950                 (flycheck-error-level-severity (flycheck-error-level err)))
   4951             (not (flycheck-has-current-errors-p min-level)))
   4952       t)))
   4953 
   4954 (defun flycheck-next-error-pos (n &optional reset)
   4955   "Get the position of the N-th next error.
   4956 
   4957 With negative N, get the position of the (-N)-th previous error
   4958 instead.  With non-nil RESET, search from `point-min', otherwise
   4959 search from the current point.
   4960 
   4961 Return the position of the next or previous error, or nil if
   4962 there is none.  If N is zero, return `point', or `point-min' if
   4963 RESET is non-nil."
   4964   (let ((n (or n 1))
   4965         (pos (if reset (point-min) (point))))
   4966     (if (>= n 0)
   4967         ;; Search forwards
   4968         (while (and pos (> n 0))
   4969           (setq n (1- n))
   4970           (when (get-char-property pos 'flycheck-error)
   4971             ;; Move beyond from the current error if any
   4972             (setq pos (next-single-char-property-change pos 'flycheck-error)))
   4973           (while (not (or (= pos (point-max))
   4974                           (flycheck-error-level-interesting-at-pos-p pos)))
   4975             ;; Scan for the next error
   4976             (setq pos (next-single-char-property-change pos 'flycheck-error)))
   4977           (when (and (= pos (point-max))
   4978                      (not (flycheck-error-level-interesting-at-pos-p pos)))
   4979             ;; If we reached the end of the buffer, but no error, we didn't find
   4980             ;; any
   4981             (setq pos nil)))
   4982       ;; Search backwards
   4983       (while (and pos (< n 0))
   4984         (setq n (1+ n))
   4985         ;; Loop until we find an error.  We need to check the position *before*
   4986         ;; the current one, because `previous-single-char-property-change'
   4987         ;; always moves to the position *of* the change.
   4988         (while (not (or (= pos (point-min))
   4989                         (flycheck-error-level-interesting-at-pos-p (1- pos))))
   4990           (setq pos (previous-single-char-property-change pos 'flycheck-error)))
   4991         (when (and (= pos (point-min))
   4992                    (not (flycheck-error-level-interesting-at-pos-p pos)))
   4993           ;; We didn't find any error.
   4994           (setq pos nil))
   4995         (when pos
   4996           ;; We found an error, so move to its beginning
   4997           (setq pos (previous-single-char-property-change pos
   4998                                                           'flycheck-error)))))
   4999     pos))
   5000 
   5001 (defun flycheck-next-error-function (n reset)
   5002   "Visit the N-th error from the current point.
   5003 
   5004 N is the number of errors to advance by, where a negative N
   5005 advances backwards.  With non-nil RESET, advance from the
   5006 beginning of the buffer, otherwise advance from the current
   5007 position.
   5008 
   5009 Intended for use with `next-error-function'."
   5010   (if-let* ((pos (flycheck-next-error-pos n reset))
   5011             (err (get-char-property pos 'flycheck-error)))
   5012       (flycheck-jump-to-error err)
   5013     (user-error "No more Flycheck errors")))
   5014 
   5015 (defun flycheck-next-error (&optional n reset)
   5016   "Visit the N-th error from the current point.
   5017 
   5018 N is the number of errors to advance by, where a negative N
   5019 advances backwards.  With non-nil RESET, advance from the
   5020 beginning of the buffer, otherwise advance from the current
   5021 position."
   5022   (interactive "P")
   5023   (when (consp n)
   5024     ;; Universal prefix argument means reset
   5025     (setq reset t n nil))
   5026   (flycheck-next-error-function n reset)
   5027   (flycheck-display-error-at-point))
   5028 
   5029 (defun flycheck-previous-error (&optional n)
   5030   "Visit the N-th previous error.
   5031 
   5032 If given, N specifies the number of errors to move backwards by.
   5033 If N is negative, move forwards instead."
   5034   (interactive "P")
   5035   (flycheck-next-error (- (or n 1))))
   5036 
   5037 (defun flycheck-first-error (&optional n)
   5038   "Visit the N-th error from beginning of the buffer.
   5039 
   5040 If given, N specifies the number of errors to move forward from
   5041 the beginning of the buffer."
   5042   (interactive "P")
   5043   (flycheck-next-error n 'reset))
   5044 
   5045 
   5046 ;;; Listing errors in buffers
   5047 (defconst flycheck-error-list-buffer "*Flycheck errors*"
   5048   "The name of the buffer to show error lists.")
   5049 
   5050 (defmacro flycheck-error-list-with-buffer (&rest body)
   5051   "Evaluate BODY in flycheck-error-list-buffer, if it exists."
   5052   (declare (indent 0) (debug t))
   5053   `(when (get-buffer flycheck-error-list-buffer)
   5054      (with-current-buffer flycheck-error-list-buffer
   5055        ,@body)))
   5056 
   5057 (defvar flycheck-error-list-mode-map
   5058   (let ((map (make-sparse-keymap)))
   5059     (define-key map (kbd "f") #'flycheck-error-list-set-filter)
   5060     (define-key map (kbd "F") #'flycheck-error-list-reset-filter)
   5061     (define-key map (kbd "n") #'flycheck-error-list-next-error)
   5062     (define-key map (kbd "p") #'flycheck-error-list-previous-error)
   5063     (define-key map (kbd "g") #'flycheck-error-list-check-source)
   5064     (define-key map (kbd "e") #'flycheck-error-list-explain-error)
   5065     (define-key map (kbd "RET") #'flycheck-error-list-goto-error)
   5066     map)
   5067   "The keymap of `flycheck-error-list-mode'.")
   5068 
   5069 (defun flycheck-error-list-make-last-column (message checker)
   5070   "Compute contents of the last error list cell.
   5071 
   5072 MESSAGE and CHECKER are displayed in a single column to allow the
   5073 message to stretch arbitrarily far."
   5074   (let ((checker-name (propertize (symbol-name checker)
   5075                                   'face 'flycheck-error-list-checker-name))
   5076         (message (propertize message
   5077                              'face 'flycheck-error-list-error-message)))
   5078     (format "%s (%s)" message checker-name)))
   5079 
   5080 (defconst flycheck-error-list-format
   5081   `[("File" 6)
   5082     ("Line" 5 flycheck-error-list-entry-< :right-align t)
   5083     ("Col" 3 nil :right-align t)
   5084     ("Level" 8 flycheck-error-list-entry-level-<)
   5085     ("ID" 6 t)
   5086     (,(flycheck-error-list-make-last-column "Message" 'Checker) 0 t)]
   5087   "Table format for the error list.")
   5088 
   5089 (defconst flycheck-error-list-padding 1
   5090   "Padding used in error list.")
   5091 
   5092 (defconst flycheck--error-list-msg-offset
   5093   (seq-reduce
   5094    (lambda (offset fmt)
   5095      (pcase-let* ((`(,_ ,width ,_ . ,props) fmt)
   5096                   (padding (or (plist-get props :pad-right) 1)))
   5097        (+ offset width padding)))
   5098    (seq-subseq flycheck-error-list-format 0 -1)
   5099    flycheck-error-list-padding)
   5100   "Amount of space to use in `flycheck-flush-multiline-message'.")
   5101 
   5102 (define-derived-mode flycheck-error-list-mode tabulated-list-mode
   5103   "Flycheck errors"
   5104   "Major mode for listing Flycheck errors.
   5105 
   5106 \\{flycheck-error-list-mode-map}"
   5107   (setq tabulated-list-format flycheck-error-list-format
   5108         ;; Sort by location initially
   5109         tabulated-list-sort-key (cons "Line" nil)
   5110         tabulated-list-padding flycheck-error-list-padding
   5111         tabulated-list-entries #'flycheck-error-list-entries
   5112         ;; `revert-buffer' updates the mode line for us, so all we need to do is
   5113         ;; set the corresponding mode line construct.
   5114         mode-line-buffer-identification flycheck-error-list-mode-line)
   5115   ;; See https://github.com/flycheck/flycheck/issues/1101
   5116   (setq-local truncate-string-ellipsis "…")
   5117   (tabulated-list-init-header))
   5118 
   5119 (defvar-local flycheck-error-list-source-buffer nil
   5120   "The current source buffer of the error list.")
   5121 ;; Needs to permanently local to preserve the source buffer across buffer
   5122 ;; reversions
   5123 (put 'flycheck-error-list-source-buffer 'permanent-local t)
   5124 
   5125 (defun flycheck-error-list-set-source (buffer)
   5126   "Set BUFFER as the source buffer of the error list."
   5127   (flycheck-error-list-with-buffer
   5128     (setq flycheck-error-list-source-buffer buffer)
   5129     (flycheck-error-list-refresh)))
   5130 
   5131 (defun flycheck-error-list-update-source ()
   5132   "Make the error list display errors from the current buffer.
   5133 
   5134 The update is skipped if the current buffer is the error list or
   5135 if the error list is already pointing to the current buffer."
   5136   (unless (memq (current-buffer)
   5137                 (list (get-buffer flycheck-error-list-buffer)
   5138                       (flycheck-error-list-with-buffer
   5139                         flycheck-error-list-source-buffer)))
   5140     (flycheck-error-list-set-source (current-buffer))))
   5141 
   5142 (defun flycheck-error-list-check-source ()
   5143   "Trigger a syntax check in the source buffer of the error list."
   5144   (interactive)
   5145   (let ((buffer (get-buffer flycheck-error-list-source-buffer)))
   5146     (when (buffer-live-p buffer)
   5147       (with-current-buffer buffer
   5148         (flycheck-buffer)))))
   5149 
   5150 (define-button-type 'flycheck-error-list
   5151   'action #'flycheck-error-list-goto-error
   5152   'help-echo "mouse-1, RET: goto error"
   5153   'face nil)
   5154 
   5155 (define-button-type 'flycheck-error-list-explain-error
   5156   'action #'flycheck-error-list-explain-error
   5157   'help-echo "mouse-1, RET: explain error")
   5158 
   5159 (defsubst flycheck-error-list-make-cell (text &optional face help-echo type)
   5160   "Make an error list cell with TEXT and FACE.
   5161 
   5162 If FACE is nil don't set a FACE on TEXT.  If TEXT already has
   5163 face properties, do not specify a FACE.  Note though, that if
   5164 TEXT gets truncated it will not inherit any previous face
   5165 properties.  If you expect TEXT to be truncated in the error
   5166 list, do specify a FACE explicitly!
   5167 
   5168 If HELP-ECHO is non-nil, set a help-echo property on TEXT, with
   5169 value HELP-ECHO.  This is convenient if you expect TEXT to be
   5170 truncated.
   5171 
   5172 The cell will have the type TYPE unless TYPE is nil, and the
   5173 default type `flycheck-error-list' will be used instead."
   5174   (append (list text 'type (if type type
   5175                              'flycheck-error-list))
   5176           (and face (list 'face face))
   5177           (and help-echo (list 'help-echo help-echo))))
   5178 
   5179 (defsubst flycheck-error-list-make-number-cell (number face)
   5180   "Make a table cell for a NUMBER with FACE.
   5181 
   5182 Convert NUMBER to string, fontify it with FACE and return the
   5183 string with attached text properties."
   5184   (flycheck-error-list-make-cell
   5185    (if (numberp number) (number-to-string number) "")
   5186    face))
   5187 
   5188 (defun flycheck-error-list-make-entry (error)
   5189   "Make a table cell for the given ERROR.
   5190 
   5191 Return a list with the contents of the table cell."
   5192   (let* ((level (flycheck-error-level error))
   5193          (level-face (flycheck-error-level-error-list-face level))
   5194          (filename (flycheck-error-filename error))
   5195          (line (flycheck-error-line error))
   5196          (column (flycheck-error-column error))
   5197          (message (or (flycheck-error-message error)
   5198                       (format "Unknown %S" level)))
   5199          (flushed-msg (flycheck-flush-multiline-message message))
   5200          (id (flycheck-error-id error))
   5201          (id-str (if id (format "%s" id) ""))
   5202          (checker (flycheck-error-checker error))
   5203          (msg-and-checker
   5204           (flycheck-error-list-make-last-column flushed-msg checker))
   5205          (explainer (flycheck-checker-get checker 'error-explainer)))
   5206     (list error
   5207           (vector (flycheck-error-list-make-cell
   5208                    (if filename
   5209                        (file-name-nondirectory filename)
   5210                      "")
   5211                    'flycheck-error-list-filename)
   5212                   (flycheck-error-list-make-number-cell
   5213                    line 'flycheck-error-list-line-number)
   5214                   (flycheck-error-list-make-number-cell
   5215                    column 'flycheck-error-list-column-number)
   5216                   (flycheck-error-list-make-cell
   5217                    (symbol-name (flycheck-error-level error)) level-face)
   5218                   ;; Error ID use a different face when an error-explainer is
   5219                   ;; present
   5220                   (flycheck-error-list-make-cell
   5221                    id-str (if explainer 'flycheck-error-list-id-with-explainer
   5222                             'flycheck-error-list-id)
   5223                    id-str 'flycheck-error-list-explain-error)
   5224                   (flycheck-error-list-make-cell
   5225                    msg-and-checker nil msg-and-checker)))))
   5226 
   5227 (defun flycheck-flush-multiline-message (msg)
   5228   "Prepare error message MSG for display in the error list.
   5229 
   5230 Prepend all lines of MSG except the first with enough space to
   5231 ensure that they line up properly once the message is displayed."
   5232   (let* ((spc-spec `(space . (:width ,flycheck--error-list-msg-offset)))
   5233          (spc (propertize " " 'display spc-spec))
   5234          (rep (concat "\\1" spc "\\2")))
   5235     (replace-regexp-in-string "\\([\r\n]+\\)\\(.\\)" rep msg)))
   5236 
   5237 (defun flycheck-error-list-current-errors ()
   5238   "Read the list of errors in `flycheck-error-list-source-buffer'."
   5239   (when (buffer-live-p flycheck-error-list-source-buffer)
   5240     (buffer-local-value 'flycheck-current-errors
   5241                         flycheck-error-list-source-buffer)))
   5242 
   5243 (defun flycheck-error-list-entries ()
   5244   "Create the entries for the error list."
   5245   (when-let* ((errors (flycheck-error-list-current-errors))
   5246               (filtered (flycheck-error-list-apply-filter errors)))
   5247     (seq-map #'flycheck-error-list-make-entry filtered)))
   5248 
   5249 (defun flycheck-error-list-entry-< (entry1 entry2)
   5250   "Determine whether ENTRY1 is before ENTRY2 by location.
   5251 
   5252 See `flycheck-error-<'."
   5253   (flycheck-error-< (car entry1) (car entry2)))
   5254 
   5255 (defun flycheck-error-list-entry-level-< (entry1 entry2)
   5256   "Determine whether ENTRY1 is before ENTRY2 by level.
   5257 
   5258 See `flycheck-error-level-<'."
   5259   (not (flycheck-error-level-< (car entry1) (car entry2))))
   5260 
   5261 (defvar flycheck-error-list-mode-line-map
   5262   (let ((map (make-sparse-keymap)))
   5263     (define-key map [mode-line mouse-1]
   5264       #'flycheck-error-list-mouse-switch-to-source)
   5265     map)
   5266   "Keymap for error list mode line.")
   5267 
   5268 (defun flycheck-error-list-propertized-source-name ()
   5269   "Get the name of the current source buffer for the mode line.
   5270 
   5271 Propertize the name of the current source buffer for use in the
   5272 mode line indication of `flycheck-error-list-mode'."
   5273   (let ((name (replace-regexp-in-string
   5274                (rx "%") "%%"
   5275                (buffer-name flycheck-error-list-source-buffer)
   5276                'fixed-case 'literal)))
   5277     (propertize name 'face 'mode-line-buffer-id
   5278                 'mouse-face 'mode-line-highlight
   5279                 'help-echo "mouse-1: switch to source"
   5280                 'local-map flycheck-error-list-mode-line-map)))
   5281 
   5282 (defun flycheck-error-list-mouse-switch-to-source (event)
   5283   "Switch to the error list source buffer of the EVENT window."
   5284   (interactive "e")
   5285   (save-selected-window
   5286     (when (eventp event)
   5287       (select-window (posn-window (event-start event))))
   5288     (when (buffer-live-p flycheck-error-list-source-buffer)
   5289       (switch-to-buffer flycheck-error-list-source-buffer))))
   5290 
   5291 (defun flycheck-get-error-list-window-list (&optional all-frames)
   5292   "Get all windows displaying the error list.
   5293 
   5294 ALL-FRAMES specifies the frames to consider, as in
   5295 `get-buffer-window-list'."
   5296   (when-let (buf (get-buffer flycheck-error-list-buffer))
   5297     (get-buffer-window-list buf nil all-frames)))
   5298 
   5299 (defun flycheck-get-error-list-window (&optional all-frames)
   5300   "Get a window displaying the error list, or nil if none.
   5301 
   5302 ALL-FRAMES specifies the frames to consider, as in
   5303 `get-buffer-window'."
   5304   (when-let (buf (get-buffer flycheck-error-list-buffer))
   5305     (get-buffer-window buf all-frames)))
   5306 
   5307 (defun flycheck-error-list-recenter-at (pos)
   5308   "Recenter the error list at POS."
   5309   (dolist (window (flycheck-get-error-list-window-list t))
   5310     (with-selected-window window
   5311       (goto-char pos)
   5312       (let ((recenter-redisplay nil))
   5313         (recenter)))))
   5314 
   5315 (defun flycheck-error-list-refresh ()
   5316   "Refresh the current error list.
   5317 
   5318 Add all errors currently reported for the current
   5319 `flycheck-error-list-source-buffer', and recenter the error
   5320 list."
   5321   ;; We only refresh the error list, when it is visible in a window, and we
   5322   ;; select this window while reverting, because Tabulated List mode attempts to
   5323   ;; recenter the error at the old location, so it must have the proper window
   5324   ;; selected.
   5325   (when-let (window (flycheck-get-error-list-window t))
   5326     (with-selected-window window
   5327       (revert-buffer))
   5328     (run-hooks 'flycheck-error-list-after-refresh-hook)
   5329     (let ((preserve-pos (eq (current-buffer)
   5330                             (get-buffer flycheck-error-list-buffer))))
   5331       ;; If the error list is the current buffer, don't recenter when
   5332       ;; highlighting
   5333       (flycheck-error-list-highlight-errors preserve-pos))))
   5334 
   5335 (defun flycheck-error-list-mode-line-filter-indicator ()
   5336   "Create a string representing the current error list filter."
   5337   (if flycheck-error-list-minimum-level
   5338       (format " [>= %s]" flycheck-error-list-minimum-level)
   5339     ""))
   5340 
   5341 (defun flycheck-error-list-set-filter (level)
   5342   "Restrict the error list to errors at level LEVEL or higher.
   5343 
   5344 LEVEL is either an error level symbol, or nil, to remove the filter."
   5345   (interactive
   5346    (list (flycheck-read-error-level
   5347           "Minimum error level (errors at lower levels will be hidden): ")))
   5348   (when (and level (not (flycheck-error-level-p level)))
   5349     (user-error "Invalid level: %s" level))
   5350   (flycheck-error-list-with-buffer
   5351     (setq-local flycheck-error-list-minimum-level level)
   5352     (force-mode-line-update)
   5353     (flycheck-error-list-refresh)
   5354     (flycheck-error-list-recenter-at (point-min))))
   5355 
   5356 (defun flycheck-error-list-reset-filter (&optional refresh)
   5357   "Remove local error filters and reset to the default filter.
   5358 
   5359 Interactively, or with non-nil REFRESH, refresh the error list."
   5360   (interactive '(t))
   5361   (flycheck-error-list-with-buffer
   5362     (kill-local-variable 'flycheck-error-list-minimum-level)
   5363     (when refresh
   5364       (flycheck-error-list-refresh)
   5365       (flycheck-error-list-recenter-at (point-min))
   5366       (force-mode-line-update))))
   5367 
   5368 (defun flycheck-error-list-apply-filter (errors)
   5369   "Filter ERRORS according to `flycheck-error-list-minimum-level'."
   5370   (if-let* ((min-level flycheck-error-list-minimum-level)
   5371             (min-severity (flycheck-error-level-severity min-level)))
   5372       (seq-filter (lambda (err) (>= (flycheck-error-level-severity
   5373                                      (flycheck-error-level err))
   5374                                     min-severity))
   5375                   errors)
   5376     errors))
   5377 
   5378 (defun flycheck-error-list-goto-error (&optional pos)
   5379   "Go to the location of the error at POS in the error list.
   5380 
   5381 POS defaults to `point'."
   5382   (interactive)
   5383   (when-let* ((error (tabulated-list-get-id pos)))
   5384     (flycheck-jump-to-error error)))
   5385 
   5386 (defun flycheck-jump-to-error (error)
   5387   "Go to the location of ERROR."
   5388   (let* ((error-copy (copy-flycheck-error error))
   5389          (filename (flycheck-error-filename error))
   5390          (other-file-error (flycheck-relevant-error-other-file-p error))
   5391          (buffer (if filename
   5392                      (find-file-noselect filename)
   5393                    (flycheck-error-buffer error))))
   5394     (when (buffer-live-p buffer)
   5395       (setf (flycheck-error-buffer error-copy) buffer)
   5396       (flycheck-jump-in-buffer buffer error-copy)
   5397       ;; When jumping to an error in another file, it may not have
   5398       ;; this error available for highlighting yet, so we trigger a check
   5399       ;; if necessary.
   5400       (when other-file-error
   5401         (with-current-buffer buffer
   5402           ;; `seq-contains-p' is only in seq >= 2.21
   5403           (unless (with-no-warnings
   5404                     (seq-contains flycheck-current-errors error-copy 'equal))
   5405             (when flycheck-mode
   5406               (flycheck-buffer))))))))
   5407 
   5408 (defun flycheck-jump-in-buffer (buffer error)
   5409   "In BUFFER, jump to ERROR."
   5410   ;; FIXME: we assume BUFFER and the buffer of ERROR are the same.  We don't
   5411   ;; need the first argument then.
   5412   (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer))
   5413       ;; When called from within the error list, keep the error list,
   5414       ;; otherwise replace the current buffer.
   5415       (pop-to-buffer buffer 'other-window)
   5416     (switch-to-buffer buffer))
   5417   (let ((pos (flycheck-error-pos error)))
   5418     (unless (eq (goto-char pos) (point))
   5419       ;; If widening gets in the way of moving to the right place, remove it
   5420       ;; and try again
   5421       (widen)
   5422       (goto-char pos)))
   5423   ;; Re-highlight the errors.  We have post-command-hook for that, but calls to
   5424   ;; `flycheck-jump-in-buffer' that come from other buffers (e.g. from the error
   5425   ;; list) won't trigger it.
   5426   (flycheck-error-list-highlight-errors 'preserve-pos))
   5427 
   5428 (defun flycheck-error-list-explain-error (&optional pos)
   5429   "Explain the error at POS in the error list.
   5430 
   5431 POS defaults to `point'."
   5432   (interactive)
   5433   (when-let* ((error (tabulated-list-get-id pos))
   5434               (explainer (flycheck-checker-get (flycheck-error-checker error)
   5435                                                'error-explainer)))
   5436     (flycheck-error-with-buffer error
   5437       (when-let (explanation (funcall explainer error))
   5438         (flycheck-display-error-explanation explanation)))))
   5439 
   5440 (defun flycheck-error-list-next-error-pos (pos &optional n)
   5441   "Starting from POS get the N'th next error in the error list.
   5442 
   5443 N defaults to 1.  If N is negative, search for the previous error
   5444 instead.
   5445 
   5446 Get the beginning position of the N'th next error from POS, or
   5447 nil, if there is no next error."
   5448   (let ((n (or n 1)))
   5449     (if (>= n 0)
   5450         ;; Search forward
   5451         (while (and pos (/= n 0))
   5452           (setq n (1- n))
   5453           (setq pos (next-single-property-change pos 'tabulated-list-id)))
   5454       ;; Search backwards
   5455       (while (/= n 0)
   5456         (setq n (1+ n))
   5457         ;; We explicitly give the limit here to explicitly have the minimum
   5458         ;; point returned, to be able to move to the first error (which starts
   5459         ;; at `point-min')
   5460         (setq pos (previous-single-property-change pos 'tabulated-list-id
   5461                                                    nil (point-min)))))
   5462     pos))
   5463 
   5464 (defun flycheck-error-list-previous-error (n)
   5465   "Go to the N'th previous error in the error list."
   5466   (interactive "P")
   5467   (flycheck-error-list-next-error (- (or n 1))))
   5468 
   5469 (defun flycheck-error-list-next-error (n)
   5470   "Go to the N'th next error in the error list."
   5471   (interactive "P")
   5472   (let ((pos (flycheck-error-list-next-error-pos (point) n)))
   5473     (when (and pos (/= pos (point)))
   5474       (goto-char pos)
   5475       (save-selected-window
   5476         ;; Keep the error list selected, so that the user can navigate errors by
   5477         ;; repeatedly pressing n/p, without having to re-select the error list
   5478         ;; window.
   5479         (flycheck-error-list-goto-error)))))
   5480 
   5481 (defvar-local flycheck-error-list-highlight-overlays nil
   5482   "Error highlight overlays in the error list buffer.")
   5483 (put 'flycheck-error-list-highlight-overlays 'permanent-local t)
   5484 
   5485 (defun flycheck-error-list-highlight-errors (&optional preserve-pos)
   5486   "Highlight errors in the error list.
   5487 
   5488 Highlight all errors in the error list that are at point in the
   5489 source buffer, and on the same line as point.  Then recenter the
   5490 error list to the highlighted error, unless PRESERVE-POS is
   5491 non-nil."
   5492   (when (get-buffer flycheck-error-list-buffer)
   5493     (with-current-buffer flycheck-error-list-buffer
   5494       (let ((current-errors
   5495              (when (buffer-live-p flycheck-error-list-source-buffer)
   5496                (with-current-buffer flycheck-error-list-source-buffer
   5497                  (flycheck-overlay-errors-in (line-beginning-position)
   5498                                              (line-end-position))))))
   5499         (let ((old-overlays flycheck-error-list-highlight-overlays)
   5500               (min-point (point-max))
   5501               (max-point (point-min)))
   5502           ;; Display the new overlays first, to avoid re-display flickering
   5503           (setq flycheck-error-list-highlight-overlays nil)
   5504           (when current-errors
   5505             (let ((next-error-pos (point-min)))
   5506               (while next-error-pos
   5507                 (let* ((beg next-error-pos)
   5508                        (end (flycheck-error-list-next-error-pos beg))
   5509                        (err (tabulated-list-get-id beg)))
   5510                   (when (member err current-errors)
   5511                     (setq min-point (min min-point beg)
   5512                           max-point (max max-point beg))
   5513                     (let ((ov (make-overlay beg
   5514                                             ;; Extend overlay to the beginning
   5515                                             ;; of the next line, to highlight
   5516                                             ;; the whole line
   5517                                             (or end (point-max)))))
   5518                       (push ov flycheck-error-list-highlight-overlays)
   5519                       (setf (overlay-get ov 'flycheck-error-highlight-overlay)
   5520                             t)
   5521                       (setf (overlay-get ov 'face)
   5522                             'flycheck-error-list-highlight)))
   5523                   (setq next-error-pos end)))))
   5524           ;; Delete the old overlays
   5525           (seq-do #'delete-overlay old-overlays)
   5526           (when (and (not preserve-pos) current-errors)
   5527             ;; Move point to the middle error
   5528             (goto-char (+ min-point (/ (- max-point min-point) 2)))
   5529             (beginning-of-line)
   5530             ;; And recenter the error list at this position
   5531             (flycheck-error-list-recenter-at (point))))))))
   5532 
   5533 (defun flycheck-list-errors ()
   5534   "Show the error list for the current buffer."
   5535   (interactive)
   5536   (unless flycheck-mode
   5537     (user-error "Flycheck mode not enabled"))
   5538   ;; Create and initialize the error list
   5539   (unless (get-buffer flycheck-error-list-buffer)
   5540     (with-current-buffer (get-buffer-create flycheck-error-list-buffer)
   5541       (flycheck-error-list-mode)))
   5542   ;; Reset the error filter
   5543   (flycheck-error-list-reset-filter)
   5544   (let ((source (current-buffer)))
   5545     ;; Show the error list in a side window.  Under some configurations of
   5546     ;; `display-buffer', this may select `flycheck-error-list-buffer' (see URL
   5547     ;; `https://github.com/flycheck/flycheck/issues/1776').
   5548     (display-buffer flycheck-error-list-buffer)
   5549     ;; Adjust the source, causing a refresh
   5550     (flycheck-error-list-set-source source)))
   5551 
   5552 (defalias 'list-flycheck-errors 'flycheck-list-errors)
   5553 
   5554 
   5555 ;;; Displaying errors in the current buffer
   5556 (defun flycheck-display-errors (errors)
   5557   "Display ERRORS using `flycheck-display-errors-function'."
   5558   (when flycheck-display-errors-function
   5559     (funcall flycheck-display-errors-function errors)))
   5560 
   5561 (defun flycheck-clear-displayed-errors ()
   5562   "Clear errors using `flycheck-clear-displayed-errors-function'."
   5563   (when flycheck-clear-displayed-errors-function
   5564     (funcall flycheck-clear-displayed-errors-function)))
   5565 
   5566 (defvar-local flycheck-display-error-at-point-timer nil
   5567   "Timer to automatically show errors.")
   5568 
   5569 (defun flycheck-cancel-error-display-error-at-point-timer ()
   5570   "Cancel the error display timer for the current buffer."
   5571   (when flycheck-display-error-at-point-timer
   5572     (cancel-timer flycheck-display-error-at-point-timer)
   5573     (setq flycheck-display-error-at-point-timer nil)))
   5574 
   5575 (defun flycheck-display-error-at-point ()
   5576   "Display all the error messages at point.
   5577 
   5578 If there are no errors, clears the error messages at point."
   5579   (interactive)
   5580   ;; This function runs from a timer, so we must take care to not ignore any
   5581   ;; errors
   5582   (with-demoted-errors "Flycheck error display error: %s"
   5583     (flycheck-cancel-error-display-error-at-point-timer)
   5584     (when flycheck-mode
   5585       (let ((errors (flycheck-overlay-errors-at (point))))
   5586         (if errors
   5587             (flycheck-display-errors errors)
   5588           (flycheck-clear-displayed-errors))))))
   5589 
   5590 (defun flycheck-display-error-at-point-soon ()
   5591   "Display error messages at point, with a delay."
   5592   (flycheck-cancel-error-display-error-at-point-timer)
   5593   (setq flycheck-display-error-at-point-timer
   5594         (run-at-time flycheck-display-errors-delay nil
   5595                      'flycheck-display-error-at-point)))
   5596 
   5597 
   5598 ;;; Functions to display errors
   5599 (defconst flycheck-error-message-buffer "*Flycheck error messages*"
   5600   "The name of the buffer to show long error messages in.")
   5601 
   5602 (defun flycheck-error-message-buffer ()
   5603   "Get the buffer object to show long error messages in.
   5604 
   5605 Get the buffer named by variable `flycheck-error-message-buffer',
   5606 or nil if the buffer does not exist."
   5607   (get-buffer flycheck-error-message-buffer))
   5608 
   5609 (defun flycheck-may-use-echo-area-p ()
   5610   "Determine whether the echo area may be used.
   5611 
   5612 The echo area may be used if the cursor is not in the echo area,
   5613 and if the echo area is not occupied by minibuffer input."
   5614   (not (or cursor-in-echo-area (active-minibuffer-window))))
   5615 
   5616 (define-derived-mode flycheck-error-message-mode text-mode
   5617   "Flycheck error messages"
   5618   "Major mode for extended error messages.")
   5619 
   5620 (defvar flycheck--last-displayed-message nil
   5621   "Reference to the last displayed message so it can be cleared.
   5622 
   5623 This value is the return value from `display-message-or-buffer',
   5624 thus it can be a string or a window.
   5625 
   5626 See `flycheck-clear-displayed-error-messages'.")
   5627 
   5628 (defun flycheck-display-error-messages (errors)
   5629   "Display the messages of ERRORS.
   5630 
   5631 Concatenate all non-nil messages of ERRORS as with
   5632 `flycheck-help-echo-all-error-messages', and display them with
   5633 `display-message-or-buffer', which shows the messages either in
   5634 the echo area or in a separate buffer, depending on the number of
   5635 lines.  See Info node `(elisp)Displaying Messages' for more
   5636 information.
   5637 
   5638 In the latter case, show messages in the buffer denoted by
   5639 variable `flycheck-error-message-buffer'."
   5640   (when (and errors (flycheck-may-use-echo-area-p))
   5641     (let* ((message (flycheck-help-echo-all-error-messages errors))
   5642            (retval (display-message-or-buffer
   5643                     message flycheck-error-message-buffer 'not-this-window)))
   5644       ;; We cannot rely on `display-message-or-buffer' returning the right
   5645       ;; window. See URL `https://github.com/flycheck/flycheck/issues/1643'.
   5646       (when-let (buf (get-buffer flycheck-error-message-buffer))
   5647         (with-current-buffer buf
   5648           (unless (derived-mode-p 'flycheck-error-message-mode)
   5649             (flycheck-error-message-mode))))
   5650       (setq flycheck--last-displayed-message retval)
   5651       retval)))
   5652 
   5653 (defun flycheck-display-error-messages-unless-error-list (errors)
   5654   "Show messages of ERRORS unless the error list is visible.
   5655 
   5656 Like `flycheck-display-error-messages', but only if the error
   5657 list (see `flycheck-list-errors') is not visible in any window in
   5658 the current frame."
   5659   (unless (flycheck-get-error-list-window 'current-frame)
   5660     (flycheck-display-error-messages errors)))
   5661 
   5662 (defun flycheck-hide-error-buffer ()
   5663   "Hide the Flycheck error buffer if necessary.
   5664 
   5665 Hide the error buffer if there is no error under point."
   5666   (when-let* ((buffer (flycheck-error-message-buffer))
   5667               (window (get-buffer-window buffer)))
   5668     (unless (flycheck-overlays-at (point))
   5669       ;; save-selected-window prevents `quit-window' from changing the current
   5670       ;; buffer (see https://github.com/flycheck/flycheck/issues/648).
   5671       (save-selected-window
   5672         (quit-window nil window)))))
   5673 
   5674 (defun flycheck-clear-displayed-error-messages ()
   5675   "Clear error messages displayed by `flycheck-display-error-messages'."
   5676   (when flycheck--last-displayed-message
   5677     (if (and (stringp flycheck--last-displayed-message)
   5678              (equal (current-message) flycheck--last-displayed-message))
   5679         (message nil)
   5680       (flycheck-hide-error-buffer))))
   5681 
   5682 
   5683 ;;; Working with errors
   5684 (defun flycheck-copy-errors-as-kill (pos &optional formatter)
   5685   "Copy each error at POS into kill ring, using FORMATTER.
   5686 
   5687 FORMATTER is a function to turn an error into a string,
   5688 defaulting to `flycheck-error-message'.
   5689 
   5690 Interactively, use `flycheck-error-format-message-and-id' as
   5691 FORMATTER with universal prefix arg, and `flycheck-error-id' with
   5692 normal prefix arg, i.e. copy the message and the ID with
   5693 universal prefix arg, and only the id with normal prefix arg."
   5694   (interactive (list (point)
   5695                      (pcase current-prefix-arg
   5696                        ((pred not) #'flycheck-error-message)
   5697                        ((pred consp) #'flycheck-error-format-message-and-id)
   5698                        (_ #'flycheck-error-id))))
   5699   (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message)
   5700                                      (flycheck-overlay-errors-at pos)))))
   5701     (when messages
   5702       (seq-do #'kill-new (reverse messages))
   5703       (message (string-join messages "\n")))))
   5704 
   5705 (defun flycheck-explain-error-at-point ()
   5706   "Display an explanation for the first explainable error at point.
   5707 
   5708 The first explainable error at point is the first error at point
   5709 with a non-nil `:error-explainer' function defined in its
   5710 checker.  The `:error-explainer' function is then called with
   5711 this error to produce the explanation to display."
   5712   (interactive)
   5713   (when-let* ((first-error
   5714                ;; Get the first error at point that has an `error-explainer'.
   5715                (seq-find (lambda (error)
   5716                            (flycheck-checker-get
   5717                             (flycheck-error-checker error) 'error-explainer))
   5718                          (flycheck-overlay-errors-at (point))))
   5719               (explainer
   5720                (flycheck-checker-get (flycheck-error-checker first-error)
   5721                                      'error-explainer))
   5722               (explanation (funcall explainer first-error)))
   5723     (flycheck-display-error-explanation explanation)))
   5724 
   5725 (defconst flycheck-explain-error-buffer "*Flycheck error explanation*"
   5726   "The name of the buffer to show error explanations.")
   5727 
   5728 (define-derived-mode flycheck-explain-error-mode help-mode
   5729   "Error explanation"
   5730   "Major mode for displaying error explanations."
   5731   (setq buffer-read-only t))
   5732 
   5733 (defun flycheck-display-error-explanation (explanation)
   5734   "Display the EXPLANATION for an error."
   5735   (pcase explanation
   5736     (`nil)
   5737     (`(url . ,url) (browse-url url))
   5738     (_ (let ((inhibit-read-only t)
   5739              (standard-output (temp-buffer-window-setup
   5740                                flycheck-explain-error-buffer)))
   5741          (with-current-buffer standard-output
   5742            (flycheck-explain-error-mode))
   5743          (cond
   5744           ((functionp explanation) (funcall explanation))
   5745           ((stringp explanation) (princ explanation))
   5746           (t (error "Unsupported error explanation: %S" explanation)))
   5747          (display-message-or-buffer standard-output nil 'not-this-window)))))
   5748 
   5749 
   5750 ;;; Syntax checkers using external commands
   5751 (defun flycheck-command-argument-p (arg)
   5752   "Check whether ARG is a valid command argument."
   5753   (pcase arg
   5754     ((pred stringp) t)
   5755     ((or `source `source-inplace `source-original) t)
   5756     (`(,(or `source `source-inplace) ,suffix)
   5757      (stringp suffix))
   5758     ((or `temporary-directory `temporary-file-name) t)
   5759     (`null-device t)
   5760     (`(config-file ,option-name ,config-file-var)
   5761      (and (stringp option-name)
   5762           (symbolp config-file-var)))
   5763     (`(config-file ,option-name ,config-file-var ,prepender)
   5764      (and (stringp option-name)
   5765           (symbolp config-file-var)
   5766           (symbolp prepender)))
   5767     (`(,(or `option `option-list) ,option-name ,option-var)
   5768      (and (stringp option-name)
   5769           (symbolp option-var)))
   5770     (`(,(or `option `option-list) ,option-name ,option-var ,prepender)
   5771      (and (stringp option-name)
   5772           (symbolp option-var)
   5773           (symbolp prepender)))
   5774     (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter)
   5775      (and (stringp option-name)
   5776           (symbolp option-var)
   5777           (symbolp prepender)
   5778           (symbolp filter)))
   5779     (`(option-flag ,option-name ,option-var)
   5780      (and (stringp option-name)
   5781           (symbolp option-var)))
   5782     (`(eval ,_) t)
   5783     (_ nil)))
   5784 
   5785 (defun flycheck-compute-working-directory (checker)
   5786   "Get the default working directory for CHECKER.
   5787 
   5788 Compute the value of `default-directory' for the invocation of
   5789 the syntax checker command, by calling the function in the
   5790 `working-directory' property of CHECKER, with CHECKER as sole
   5791 argument, and returning its value.  Signal an error if the
   5792 function returns a non-existing working directory.
   5793 
   5794 If the property is undefined or if the function returns nil
   5795 return the `default-directory' of the current buffer."
   5796   (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory))
   5797          (directory (or (and def-directory-fn
   5798                              (funcall def-directory-fn checker))
   5799                         ;; Default to the `default-directory' of the current
   5800                         ;; buffer
   5801                         default-directory)))
   5802     (unless (file-exists-p directory)
   5803       (error ":working-directory %s of syntax checker %S does not exist"
   5804              directory checker))
   5805     directory))
   5806 
   5807 ;;;###autoload
   5808 (defun flycheck-define-command-checker (symbol docstring &rest properties)
   5809   "Define SYMBOL as syntax checker to run a command.
   5810 
   5811 Define SYMBOL as generic syntax checker via
   5812 `flycheck-define-generic-checker', which uses an external command
   5813 to check the buffer.  SYMBOL and DOCSTRING are the same as for
   5814 `flycheck-define-generic-checker'.
   5815 
   5816 In addition to the properties understood by
   5817 `flycheck-define-generic-checker', the following PROPERTIES
   5818 constitute a command syntax checker.  Unless otherwise noted, all
   5819 properties are mandatory.  Note that the default `:error-filter'
   5820 of command checkers is `flycheck-sanitize-errors'.
   5821 
   5822 `:command COMMAND'
   5823      The command to run for syntax checking.
   5824 
   5825      COMMAND is a list of the form `(EXECUTABLE [ARG ...])'.
   5826 
   5827      EXECUTABLE is a string with the executable of this syntax
   5828      checker.  It can be overridden with the variable
   5829      `flycheck-SYMBOL-executable'.  Note that this variable is
   5830      NOT implicitly defined by this function.  Use
   5831      `flycheck-def-executable-var' to define this variable.
   5832 
   5833      Each ARG is an argument to the executable, either as string,
   5834      or as special symbol or form for
   5835      `flycheck-substitute-argument', which see.
   5836 
   5837 `:error-patterns PATTERNS'
   5838      A list of patterns to parse the output of the `:command'.
   5839 
   5840      Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where
   5841      LEVEL is a Flycheck error level (see
   5842      `flycheck-define-error-level'), followed by one or more RX
   5843      `SEXP's which parse an error of that level and extract line,
   5844      column, file name and the message.
   5845 
   5846      See `rx' for general information about RX, and
   5847      `flycheck-rx-to-string' for some special RX forms provided
   5848      by Flycheck.
   5849 
   5850      All patterns are applied in the order of declaration to the
   5851      whole output of the syntax checker.  Output already matched
   5852      by a pattern will not be matched by subsequent patterns.  In
   5853      other words, the first pattern wins.
   5854 
   5855      This property is optional.  If omitted, however, an
   5856      `:error-parser' is mandatory.
   5857 
   5858 `:error-parser FUNCTION'
   5859      A function to parse errors with.
   5860 
   5861      The function shall accept three arguments OUTPUT CHECKER
   5862      BUFFER.  OUTPUT is the syntax checker output as string,
   5863      CHECKER the syntax checker that was used, and BUFFER a
   5864      buffer object representing the checked buffer.  The function
   5865      must return a list of `flycheck-error' objects parsed from
   5866      OUTPUT.
   5867 
   5868      This property is optional.  If omitted, it defaults to
   5869      `flycheck-parse-with-patterns'.  In this case,
   5870      `:error-patterns' is mandatory.
   5871 
   5872 `:standard-input t'
   5873      Whether to send the buffer contents on standard input.
   5874 
   5875      If this property is given and has a non-nil value, send the
   5876      contents of the buffer on standard input.
   5877 
   5878      Some checkers that support reading from standard input have
   5879      a separate flag to indicate the name of the file whose
   5880      contents are being passed on standard input (typically
   5881      `stdin-filename').  In that case, use the `(option)' form in
   5882      `:command' to pass the value of variable `buffer-file-name'
   5883      when the current buffer has a file name (that is,
   5884      use `option \"--stdin-file-name\" buffer-file-name').
   5885 
   5886      For buffers not backed by files, checkers that support input
   5887      on stdin typically report a file name like `-' or `<stdin>'.
   5888      Make sure your error parser or patterns expect these file
   5889      names (for example, use `(or \"<stdin>\" (file-name))') or
   5890      call `flycheck-remove-error-file-names' in a custom
   5891      `:error-filter'.
   5892 
   5893      Defaults to nil.
   5894 
   5895 Note that you may not give `:start', `:interrupt', and
   5896 `:print-doc' for a command checker.  You can give a custom
   5897 `:verify' function, though, whose results will be appended to the
   5898 default `:verify' function of command checkers."
   5899   (declare (indent 1)
   5900            (doc-string 2))
   5901   (dolist (prop '(:start :interrupt :print-doc))
   5902     (when (plist-get properties prop)
   5903       (error "%s not allowed in definition of command syntax checker %s"
   5904              prop symbol)))
   5905 
   5906   (unless (plist-get properties :error-filter)
   5907     ;; Default to `flycheck-sanitize-errors' as error filter
   5908     (setq properties (plist-put properties :error-filter
   5909                                 #'flycheck-sanitize-errors)))
   5910   (let ((verify-fn (plist-get properties :verify)))
   5911     (setq properties
   5912           (plist-put properties :verify
   5913                      (lambda (checker)
   5914                        (append (flycheck-verify-command-checker checker)
   5915                                (and verify-fn
   5916                                     (funcall verify-fn checker)))))))
   5917 
   5918   (let ((command (plist-get properties :command))
   5919         (patterns (plist-get properties :error-patterns))
   5920         (parser (or (plist-get properties :error-parser)
   5921                     #'flycheck-parse-with-patterns))
   5922         (enabled (plist-get properties :enabled))
   5923         (standard-input (plist-get properties :standard-input)))
   5924     (unless command
   5925       (error "Missing :command in syntax checker %s" symbol))
   5926     (unless (stringp (car command))
   5927       (error "Command executable for syntax checker %s must be a string: %S"
   5928              symbol (car command)))
   5929     (dolist (arg (cdr command))
   5930       (unless (flycheck-command-argument-p arg)
   5931         (error "Invalid command argument %S in syntax checker %s" arg symbol)))
   5932     (when (and (eq parser 'flycheck-parse-with-patterns)
   5933                (not patterns))
   5934       (error "Missing :error-patterns in syntax checker %s" symbol))
   5935 
   5936     (setq properties
   5937           ;; Automatically disable command checkers if the executable does not
   5938           ;; exist.
   5939           (plist-put properties :enabled
   5940                      (lambda ()
   5941                        (and (flycheck-find-checker-executable symbol)
   5942                             (flycheck-temp-files-writable-p symbol)
   5943                             (or (not enabled) (funcall enabled))))))
   5944 
   5945     (apply #'flycheck-define-generic-checker symbol docstring
   5946            :start #'flycheck-start-command-checker
   5947            :interrupt #'flycheck-interrupt-command-checker
   5948            :print-doc #'flycheck-command-checker-print-doc
   5949            properties)
   5950 
   5951     ;; Pre-compile all errors patterns into strings, so that we don't need to do
   5952     ;; that on each error parse
   5953     (let ((patterns (seq-map (lambda (p)
   5954                                (cons (flycheck-rx-to-string `(and ,@(cdr p))
   5955                                                             'no-group)
   5956                                      (car p)))
   5957                              patterns)))
   5958       (pcase-dolist (`(,prop . ,value)
   5959                      `((command        . ,command)
   5960                        (error-parser   . ,parser)
   5961                        (error-patterns . ,patterns)
   5962                        (standard-input . ,standard-input)))
   5963         (setf (flycheck-checker-get symbol prop) value)))))
   5964 
   5965 (eval-and-compile
   5966   ;; Make this function available during byte-compilation, since we need it
   5967   ;; at macro expansion of `flycheck-def-executable-var'.
   5968   (defun flycheck-checker-executable-variable (checker)
   5969     "Get the executable variable of CHECKER.
   5970 
   5971 The executable variable is named `flycheck-CHECKER-executable'."
   5972     (intern (format "flycheck-%s-executable" checker))))
   5973 
   5974 (defun flycheck-checker-default-executable (checker)
   5975   "Get the default executable of CHECKER."
   5976   (car (flycheck-checker-get checker 'command)))
   5977 
   5978 (defun flycheck-checker-executable (checker)
   5979   "Get the command executable of CHECKER.
   5980 
   5981 The executable is either the value of the variable
   5982 `flycheck-CHECKER-executable', or the default executable given in
   5983 the syntax checker definition, if the variable is nil."
   5984   (let ((var (flycheck-checker-executable-variable checker)))
   5985     (or (and (boundp var) (symbol-value var))
   5986         (flycheck-checker-default-executable checker))))
   5987 
   5988 (defun flycheck-find-checker-executable (checker)
   5989   "Get the full path of the executable of CHECKER.
   5990 
   5991 Return the full absolute path to the executable of CHECKER, or
   5992 nil if the executable does not exist."
   5993   (funcall flycheck-executable-find (flycheck-checker-executable checker)))
   5994 
   5995 (defun flycheck-call-checker-process
   5996     (checker infile destination error &rest args)
   5997   "Call CHECKER's executable with ARGS.
   5998 
   5999 Return nil (or raise an error if ERROR is non-nil) when CHECKER's
   6000 executable cannot be found, and return a numeric exit status or a
   6001 signal description string otherwise.  CHECKER's input is taken
   6002 from INFILE, and its output is sent to DESTINATION, as in
   6003 `call-process'."
   6004   (if-let (executable (flycheck-find-checker-executable checker))
   6005       (condition-case err
   6006           (apply #'call-process executable infile destination nil args)
   6007         (error (when error (signal (car err) (cdr err)))))
   6008     (when error
   6009       (user-error "Cannot find `%s' using `flycheck-executable-find'"
   6010                   (flycheck-checker-executable checker)))))
   6011 
   6012 (defun flycheck-call-checker-process-for-output
   6013     (checker infile error &rest args)
   6014   "Call CHECKER's executable with ARGS and return its output.
   6015 
   6016 Call `flycheck-call-checker-process' with INFILE, ERROR, and
   6017 ARGS.  If it returns 0, return the process' output.  Otherwise,
   6018 return nil or throw an error.
   6019 
   6020 This function is similar to `flycheck-call-checker-process'
   6021 called in a `with-output-to-string' block, but it takes care of
   6022 the error checking automatically."
   6023   (let ((temp (generate-new-buffer " *temp*")))
   6024     (unwind-protect
   6025         ;; We need to call the checker process in the right buffer, so that it
   6026         ;; uses the right exec-path, checker executable, etc.  See URL
   6027         ;; `https://github.com/flycheck/flycheck/issues/1770'.
   6028         (let ((exit-code (apply #'flycheck-call-checker-process
   6029                                 checker infile temp error args))
   6030               (output (with-current-buffer temp (buffer-string))))
   6031           (if (eql 0 exit-code) output
   6032             (when error
   6033               (error "Process %s failed with %S (%s)"
   6034                      checker exit-code output))))
   6035       (kill-buffer temp))))
   6036 
   6037 (defun flycheck-checker-arguments (checker)
   6038   "Get the command arguments of CHECKER."
   6039   (cdr (flycheck-checker-get checker 'command)))
   6040 
   6041 (defun flycheck-substitute-argument (arg checker)
   6042   "Substitute ARG for CHECKER.
   6043 
   6044 Return a list of real arguments for the executable of CHECKER,
   6045 substituted for the symbolic argument ARG.  Single arguments,
   6046 e.g. if ARG is a literal strings, are wrapped in a list.
   6047 
   6048 ARG may be one of the following forms:
   6049 
   6050 STRING
   6051      Return ARG unchanged.
   6052 
   6053 `source', `source-inplace'
   6054      Create a temporary file to check and return its path.  With
   6055      `source-inplace' create the temporary file in the same
   6056      directory as the original file.  The value of
   6057      `flycheck-temp-prefix' is used as prefix of the file name.
   6058 
   6059      With `source', try to retain the non-directory component of
   6060      the buffer's file name in the temporary file.
   6061 
   6062      `source' is the preferred way to pass the input file to a
   6063      syntax checker.  `source-inplace' should only be used if the
   6064      syntax checker needs other files from the source directory,
   6065      such as include files in C.
   6066 
   6067 `(source SUFFIX)', `(source-inplace SUFFIX)'
   6068      Like `source' and `source-inplace', but ensure generated
   6069      file names end with the given suffix.  Use this when the
   6070      checker requires that file names on its command line have a
   6071      certain suffix (file extension).
   6072 
   6073 `source-original'
   6074      Return the path of the actual file to check, or an empty
   6075      string if the buffer has no file name.
   6076 
   6077      Note that the contents of the file may not be up to date
   6078      with the contents of the buffer to check.  Do not use this
   6079      as primary input to a checker, unless absolutely necessary.
   6080 
   6081      When using this symbol as primary input to the syntax
   6082      checker, add `flycheck-buffer-saved-p' to the `:predicate'.
   6083 
   6084 `temporary-directory'
   6085      Create a unique temporary directory and return its path.
   6086 
   6087 `temporary-file-name'
   6088      Return a unique temporary filename.  The file is *not*
   6089      created.
   6090 
   6091      To ignore the output of syntax checkers, try symbol
   6092      `null-device' first.
   6093 
   6094 symbol `null-device'
   6095      Return the value of variable `null-device', i.e the system
   6096      null device.
   6097 
   6098      Use this option to ignore the output of a syntax checker.
   6099      If the syntax checker cannot handle the null device, or
   6100      won't write to an existing file, try `temporary-file-name'
   6101      instead.
   6102 
   6103 `(config-file OPTION VARIABLE [PREPEND-FN])'
   6104      Search the configuration file bound to VARIABLE with
   6105      `flycheck-locate-config-file' and return a list of arguments
   6106      that pass this configuration file to the syntax checker, or
   6107      nil if the configuration file was not found.
   6108 
   6109      PREPEND-FN is called with the OPTION and the located
   6110      configuration file, and should return OPTION prepended
   6111      before the file, either a string or as list.  If omitted,
   6112      PREPEND-FN defaults to `list'.
   6113 
   6114 `(option OPTION VARIABLE [PREPEND-FN [FILTER]])'
   6115      Retrieve the value of VARIABLE and return a list of
   6116      arguments that pass this value as value for OPTION to the
   6117      syntax checker.
   6118 
   6119      PREPEND-FN is called with the OPTION and the value of
   6120      VARIABLE, and should return OPTION prepended before the
   6121      file, either a string or as list.  If omitted, PREPEND-FN
   6122      defaults to `list'.
   6123 
   6124      FILTER is an optional function to be applied to the value of
   6125      VARIABLE before prepending.  This function must return nil
   6126      or a string.  In the former case, return nil.  In the latter
   6127      case, return a list of arguments as described above.
   6128 
   6129 `(option-list OPTION VARIABLE [PREPEND-FN [FILTER]])'
   6130      Retrieve the value of VARIABLE, which must be a list,
   6131      and prepend OPTION before each item in this list, using
   6132      PREPEND-FN.
   6133 
   6134      PREPEND-FN is called with the OPTION and each item of the
   6135      list as second argument, and should return OPTION prepended
   6136      before the item, either as string or as list.  If omitted,
   6137      PREPEND-FN defaults to `list'.
   6138 
   6139      FILTER is an optional function to be applied to each item in
   6140      the list before prepending OPTION.  It shall return the
   6141      option value for each item as string, or nil, if the item is
   6142      to be ignored.
   6143 
   6144 `(option-flag OPTION VARIABLE)'
   6145      Retrieve the value of VARIABLE and return OPTION, if the
   6146      value is non-nil.  Otherwise return nil.
   6147 
   6148 `(eval FORM)'
   6149      Return the result of evaluating FORM in the buffer to be
   6150      checked.  FORM must either return a string or a list of
   6151      strings, or nil to indicate that nothing should be
   6152      substituted for CELL.  For all other return types, signal an
   6153      error
   6154 
   6155      _No_ further substitutions are performed, neither in FORM
   6156      before it is evaluated, nor in the result of evaluating
   6157      FORM.
   6158 
   6159 In all other cases, signal an error.
   6160 
   6161 Note that substitution is *not* recursive.  No symbols or cells
   6162 are substituted within the body of cells!"
   6163   (pcase arg
   6164     ((pred stringp) (list arg))
   6165     (`source
   6166      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)))
   6167     (`source-inplace
   6168      (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)))
   6169     (`(source ,suffix)
   6170      (list (flycheck-save-buffer-to-temp
   6171             (lambda (filename) (flycheck-temp-file-system filename suffix)))))
   6172     (`(source-inplace ,suffix)
   6173      (list (flycheck-save-buffer-to-temp
   6174             (lambda (filename) (flycheck-temp-file-inplace filename suffix)))))
   6175     (`source-original (list (or (buffer-file-name) "")))
   6176     (`temporary-directory (list (flycheck-temp-dir-system)))
   6177     (`temporary-file-name
   6178      (let ((directory (flycheck-temp-dir-system)))
   6179        (list (make-temp-name (expand-file-name "flycheck" directory)))))
   6180     (`null-device (list null-device))
   6181     (`(config-file ,option-name ,file-name-var)
   6182      (when-let* ((value (symbol-value file-name-var))
   6183                  (file-name (flycheck-locate-config-file value checker)))
   6184        (flycheck-prepend-with-option option-name (list file-name))))
   6185     (`(config-file ,option-name ,file-name-var ,prepend-fn)
   6186      (when-let* ((value (symbol-value file-name-var))
   6187                  (file-name (flycheck-locate-config-file value checker)))
   6188        (flycheck-prepend-with-option option-name (list file-name) prepend-fn)))
   6189     (`(option ,option-name ,variable)
   6190      (when-let (value (symbol-value variable))
   6191        (unless (stringp value)
   6192          (error "Value %S of %S for option %s is not a string"
   6193                 value variable option-name))
   6194        (flycheck-prepend-with-option option-name (list value))))
   6195     (`(option ,option-name ,variable ,prepend-fn)
   6196      (when-let (value (symbol-value variable))
   6197        (unless (stringp value)
   6198          (error "Value %S of %S for option %s is not a string"
   6199                 value variable option-name))
   6200        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
   6201     (`(option ,option-name ,variable ,prepend-fn ,filter)
   6202      (when-let (value (funcall filter (symbol-value variable)))
   6203        (unless (stringp value)
   6204          (error "Value %S of %S (filter: %S) for option %s is not a string"
   6205                 value variable filter option-name))
   6206        (flycheck-prepend-with-option option-name (list value) prepend-fn)))
   6207     (`(option-list ,option-name ,variable)
   6208      (let ((value (symbol-value variable)))
   6209        (unless (and (listp value) (seq-every-p #'stringp value))
   6210          (error "Value %S of %S for option %S is not a list of strings"
   6211                 value variable option-name))
   6212        (flycheck-prepend-with-option option-name value)))
   6213     (`(option-list ,option-name ,variable ,prepend-fn)
   6214      (let ((value (symbol-value variable)))
   6215        (unless (and (listp value) (seq-every-p #'stringp value))
   6216          (error "Value %S of %S for option %S is not a list of strings"
   6217                 value variable option-name))
   6218        (flycheck-prepend-with-option option-name value prepend-fn)))
   6219     (`(option-list ,option-name ,variable ,prepend-fn ,filter)
   6220      (let ((value (delq nil (seq-map filter (symbol-value variable)))))
   6221        (unless (and (listp value) (seq-every-p #'stringp value))
   6222          (error "Value %S of %S for option %S is not a list of strings"
   6223                 value variable option-name))
   6224        (flycheck-prepend-with-option option-name value prepend-fn)))
   6225     (`(option-flag ,option-name ,variable)
   6226      (when (symbol-value variable)
   6227        (list option-name)))
   6228     (`(eval ,form)
   6229      (let ((result (eval form)))
   6230        (cond
   6231         ((and (listp result) (seq-every-p #'stringp result)) result)
   6232         ((stringp result) (list result))
   6233         (t (error "Invalid result from evaluation of %S: %S" form result)))))
   6234     (_ (error "Unsupported argument %S" arg))))
   6235 
   6236 (defun flycheck-checker-substituted-arguments (checker)
   6237   "Get the substituted arguments of a CHECKER.
   6238 
   6239 Substitute each argument of CHECKER using
   6240 `flycheck-substitute-argument'.  This replaces any special
   6241 symbols in the command."
   6242   (apply #'append
   6243          (seq-map (lambda (arg) (flycheck-substitute-argument arg checker))
   6244                   (flycheck-checker-arguments checker))))
   6245 
   6246 (defun flycheck--process-send-buffer-contents-chunked (process)
   6247   "Send contents of current buffer to PROCESS in small batches.
   6248 
   6249 Send the entire buffer to the standard input of PROCESS in chunks
   6250 of 4096 characters.  Chunking is done in Emacs Lisp, hence this
   6251 function is probably far less efficient than
   6252 `send-process-region'.  Use only when required."
   6253   (let ((from (point-min)))
   6254     (while (< from (point-max))
   6255       (let ((to (min (+ from 4096) (point-max))))
   6256         (process-send-region process from to)
   6257         (setq from to)))))
   6258 
   6259 (defvar flycheck-chunked-process-input
   6260   ;; Chunk process output on Windows to work around
   6261   ;; https://github.com/flycheck/flycheck/issues/794 and
   6262   ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344.  The presence of
   6263   ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1) where pipe
   6264   ;; writes on Windows are fixed.
   6265   ;;
   6266   ;; TODO: Remove option and chunking when dropping Emacs 24 support, see
   6267   ;; https://github.com/flycheck/flycheck/issues/856
   6268   (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size)))
   6269   "If non-nil send process input in small chunks.
   6270 
   6271 If this variable is non-nil `flycheck-process-send-buffer' sends
   6272 buffer contents in small chunks.
   6273 
   6274 Defaults to nil, except on Windows to work around Emacs bug
   6275 #22344.")
   6276 
   6277 (defun flycheck-process-send-buffer (process)
   6278   "Send all contents of current buffer to PROCESS.
   6279 
   6280 Sends all contents of the current buffer to the standard input of
   6281 PROCESS, and terminates standard input with EOF.
   6282 
   6283 If `flycheck-chunked-process-input' is non-nil, send buffer
   6284 contents in chunks via
   6285 `flycheck--process-send-buffer-contents-chunked', which see.
   6286 Otherwise use `process-send-region' to send all contents at once
   6287 and rely on Emacs' own buffering and chunking."
   6288   (save-restriction
   6289     (widen)
   6290     (if flycheck-chunked-process-input
   6291         (flycheck--process-send-buffer-contents-chunked process)
   6292       (process-send-region process (point-min) (point-max))))
   6293   (process-send-eof process))
   6294 
   6295 (defun flycheck--wrap-command (prog args)
   6296   "Wrap PROG and ARGS using `flycheck-command-wrapper-function'."
   6297   ;; We don't call `flycheck-executable-find' on the output of the wrapper
   6298   ;; function, since it might not expect it (an executable-find function
   6299   ;; designed to find binaries in a sandbox could get confused if we asked it
   6300   ;; about the sandboxing program itself).
   6301   (funcall flycheck-command-wrapper-function (cons prog args)))
   6302 
   6303 (defun flycheck-start-command-checker (checker callback)
   6304   "Start a command CHECKER with CALLBACK."
   6305   (let (process)
   6306     (condition-case err
   6307         (let* ((program (flycheck-find-checker-executable checker))
   6308                (args (flycheck-checker-substituted-arguments checker))
   6309                (command (flycheck--wrap-command program args))
   6310                (sentinel-events nil)
   6311                ;; Use pipes to receive output from the syntax checker.  They are
   6312                ;; more efficient and more robust than PTYs, which Emacs uses by
   6313                ;; default, and since we don't need any job control features, we
   6314                ;; can easily use pipes.
   6315                (process-connection-type nil))
   6316           ;; We pass do not associate the process with any buffer, by
   6317           ;; passing nil for the BUFFER argument of `start-process'.
   6318           ;; Instead, we just remember the buffer being checked in a
   6319           ;; process property (see below).  This neatly avoids all
   6320           ;; side-effects implied by attached a process to a buffer, which
   6321           ;; may cause conflicts with other packages.
   6322           ;;
   6323           ;; See https://github.com/flycheck/flycheck/issues/298 for an
   6324           ;; example for such a conflict.
   6325           (setq process (apply 'start-process (format "flycheck-%s" checker)
   6326                                nil command))
   6327           ;; Process sentinels can be called while sending input to the process.
   6328           ;; We want to record errors raised by process-send before calling
   6329           ;; `flycheck-handle-signal', so initially just accumulate events.
   6330           (setf (process-sentinel process)
   6331                 (lambda (_ event) (push event sentinel-events)))
   6332           (setf (process-filter process) #'flycheck-receive-checker-output)
   6333           (set-process-query-on-exit-flag process nil)
   6334           ;; Remember the syntax checker, the buffer and the callback
   6335           (process-put process 'flycheck-checker checker)
   6336           (process-put process 'flycheck-callback callback)
   6337           (process-put process 'flycheck-buffer (current-buffer))
   6338           ;; The default directory is bound in the `flycheck-syntax-check-start'
   6339           ;; function.
   6340           (process-put process 'flycheck-working-directory default-directory)
   6341           ;; Track the temporaries created by argument substitution in the
   6342           ;; process itself, to get rid of the global state ASAP.
   6343           (process-put process 'flycheck-temporaries flycheck-temporaries)
   6344           (setq flycheck-temporaries nil)
   6345           ;; Send the buffer to the process on standard input, if enabled.
   6346           (when (flycheck-checker-get checker 'standard-input)
   6347             (condition-case err
   6348                 (flycheck-process-send-buffer process)
   6349               ;; Some checkers exit before reading all input, causing errors
   6350               ;; such as a `file-error' for a closed pipe, or a plain “no longer
   6351               ;; connected to pipe; closed it” error for a disconnection.  We
   6352               ;; report them if needed in `flycheck-finish-checker-process' (see
   6353               ;; `https://github.com/flycheck/flycheck/issues/1278').
   6354               (error (process-put process 'flycheck-error err))))
   6355           ;; Set the actual sentinel and process any events that might have
   6356           ;; happened while we were sending input.
   6357           (setf (process-sentinel process) #'flycheck-handle-signal)
   6358           (dolist (event (nreverse sentinel-events))
   6359             (flycheck-handle-signal process event))
   6360           ;; Return the process.
   6361           process)
   6362       (error
   6363        ;; In case of error, clean up our resources, and report the error back to
   6364        ;; Flycheck.
   6365        (flycheck-safe-delete-temporaries)
   6366        (when process
   6367          ;; No need to explicitly delete the temporary files of the process,
   6368          ;; because deleting runs the sentinel, which will delete them anyway.
   6369          (delete-process process))
   6370        (signal (car err) (cdr err))))))
   6371 
   6372 (defun flycheck-interrupt-command-checker (_checker process)
   6373   "Interrupt a PROCESS."
   6374   ;; Deleting the process always triggers the sentinel, which does the cleanup
   6375   (when process
   6376     (delete-process process)))
   6377 
   6378 (defun flycheck-command-checker-print-doc (checker)
   6379   "Print additional documentation for a command CHECKER."
   6380   (let ((executable (flycheck-checker-default-executable checker))
   6381         (config-file-var (flycheck-checker-get checker 'config-file-var))
   6382         (option-vars (seq-sort #'string<
   6383                                (flycheck-checker-get checker 'option-vars))))
   6384     (princ "\n")
   6385 
   6386     (let ((doc-start (with-current-buffer standard-output (point-max))))
   6387       ;; Track the start of our documentation so that we can re-indent it
   6388       ;; properly
   6389       (princ "  This syntax checker executes \"")
   6390       (princ executable)
   6391       (princ "\"")
   6392       (when config-file-var
   6393         (princ ", using a configuration file from `")
   6394         (princ (symbol-name config-file-var))
   6395         (princ "'"))
   6396       (princ ". The executable can be overridden with `")
   6397       (princ (symbol-name (flycheck-checker-executable-variable checker)))
   6398       (princ "'.")
   6399 
   6400       (with-current-buffer standard-output
   6401         (save-excursion
   6402           (fill-region-as-paragraph doc-start (point-max)))))
   6403     (princ "\n")
   6404     (when option-vars
   6405       (princ
   6406        "\n  This syntax checker can be configured with these options:\n\n")
   6407       (dolist (var option-vars)
   6408         (princ (format "     * `%s'\n" var))))))
   6409 
   6410 (defun flycheck-verify-command-checker (checker)
   6411   "Verify a command CHECKER in the current buffer.
   6412 
   6413 Return a list of `flycheck-verification-result' objects for
   6414 CHECKER."
   6415   (let ((executable (flycheck-find-checker-executable checker))
   6416         (config-file-var (flycheck-checker-get checker 'config-file-var)))
   6417     `(
   6418       ,(flycheck-verification-result-new
   6419         :label "executable"
   6420         :message (if executable (format "Found at %s" executable) "Not found")
   6421         :face (if executable 'success '(bold error)))
   6422       ,@(when config-file-var
   6423           (let* ((value (symbol-value config-file-var))
   6424                  (path (and value (flycheck-locate-config-file value checker))))
   6425             (list (flycheck-verification-result-new
   6426                    :label "configuration file"
   6427                    :message (if path (format "Found at %S" path) "Not found")
   6428                    :face (if path 'success 'warning)))))
   6429       ,@(when (not (flycheck-temp-files-writable-p checker))
   6430           (list (flycheck-verification-result-new
   6431                  :label "temp directory"
   6432                  :message (format "%s is not writable"
   6433                                   (flycheck-temp-directory checker))
   6434                  :face 'error))))))
   6435 
   6436 
   6437 ;;; Process management for command syntax checkers
   6438 (defun flycheck-receive-checker-output (process output)
   6439   "Receive a syntax checking PROCESS OUTPUT."
   6440   (push output (process-get process 'flycheck-pending-output)))
   6441 
   6442 (defun flycheck-get-output (process)
   6443   "Get the complete output of PROCESS."
   6444   (with-demoted-errors "Error while retrieving process output: %S"
   6445     (let ((pending-output (process-get process 'flycheck-pending-output)))
   6446       (apply #'concat (nreverse pending-output)))))
   6447 
   6448 (defun flycheck-handle-signal (process _event)
   6449   "Handle a signal from the syntax checking PROCESS.
   6450 
   6451 _EVENT is ignored."
   6452   (when (memq (process-status process) '(signal exit))
   6453     (let ((files (process-get process 'flycheck-temporaries))
   6454           (buffer (process-get process 'flycheck-buffer))
   6455           (callback (process-get process 'flycheck-callback))
   6456           (cwd (process-get process 'flycheck-working-directory))
   6457           (err (process-get process 'flycheck-error)))
   6458       ;; Delete the temporary files
   6459       (seq-do #'flycheck-safe-delete files)
   6460       (when (buffer-live-p buffer)
   6461         (with-current-buffer buffer
   6462           (condition-case err
   6463               (pcase (process-status process)
   6464                 (`signal
   6465                  (funcall callback 'interrupted))
   6466                 (`exit
   6467                  (flycheck-finish-checker-process
   6468                   (process-get process 'flycheck-checker)
   6469                   (or err (process-exit-status process))
   6470                   files
   6471                   (flycheck-get-output process) callback cwd)))
   6472             ((debug error)
   6473              (funcall callback 'errored (error-message-string err)))))))))
   6474 
   6475 (defun flycheck-finish-checker-process
   6476     (checker exit-status files output callback cwd)
   6477   "Finish a checker process from CHECKER with EXIT-STATUS.
   6478 
   6479 EXIT-STATUS can be a number or an arbitrary form (if it is not 0,
   6480 a `suspicious' status is reported to CALLBACK).
   6481 
   6482 FILES is a list of files given as input to the checker.  OUTPUT
   6483 is the output of the syntax checker.  CALLBACK is the status
   6484 callback to use for reporting.
   6485 
   6486 Parse the OUTPUT and report an appropriate error status.
   6487 
   6488 Resolve all errors in OUTPUT using CWD as working directory."
   6489   (let ((errors (flycheck-parse-output output checker (current-buffer))))
   6490     (when (and (not (equal exit-status 0)) (null errors))
   6491       ;; Warn about a suspicious result from the syntax checker.  We do right
   6492       ;; after parsing the errors, before filtering, because a syntax checker
   6493       ;; might report errors from other files (e.g. includes) even if there
   6494       ;; are no errors in the file being checked.
   6495       (funcall callback 'suspicious
   6496                (format "Flycheck checker %S returned %S, but \
   6497 its output contained no errors: %s\nTry installing a more \
   6498 recent version of %S, and please open a bug report if the issue \
   6499 persists in the latest release.  Thanks!"  checker exit-status
   6500 output checker)))
   6501     (funcall callback 'finished
   6502              ;; Fix error file names, by substituting them backwards from the
   6503              ;; temporaries.
   6504              (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd))
   6505                       errors))))
   6506 
   6507 
   6508 ;;; Executables of command checkers.
   6509 (defmacro flycheck-def-executable-var (checker default-executable)
   6510   "Define the executable variable for CHECKER.
   6511 
   6512 DEFAULT-EXECUTABLE is the default executable.  It is only used in
   6513 the docstring of the variable.
   6514 
   6515 The variable is defined with `defcustom' in the
   6516 `flycheck-executables' group.  It's also defined to be risky as
   6517 file-local variable, to avoid arbitrary executables being used
   6518 for syntax checking."
   6519   (let ((executable-var (flycheck-checker-executable-variable checker)))
   6520     `(progn
   6521        (defcustom ,executable-var nil
   6522          ,(format "The executable of the %s syntax checker.
   6523 
   6524 Either a string containing the name or the path of the
   6525 executable, or nil to use the default executable from the syntax
   6526 checker declaration.
   6527 
   6528 The default executable is %S." checker default-executable)
   6529          :type '(choice (const :tag "Default executable" nil)
   6530                         (string :tag "Name or path"))
   6531          :group 'flycheck-executables
   6532          :risky t))))
   6533 
   6534 (defun flycheck-set-checker-executable (checker &optional executable)
   6535   "Set the executable of CHECKER in the current buffer.
   6536 
   6537 CHECKER is a syntax checker symbol.  EXECUTABLE is a string with
   6538 the name of an executable or the path to an executable file, which
   6539 is to be used as executable for CHECKER.  If omitted or nil,
   6540 reset the executable of CHECKER.
   6541 
   6542 Interactively, prompt for a syntax checker and an executable
   6543 file, and set the executable of the selected syntax checker.
   6544 With prefix arg, prompt for a syntax checker only, and reset the
   6545 executable of the select checker to the default.
   6546 
   6547 Set the executable variable of CHECKER, that is,
   6548 `flycheck-CHECKER-executable' to EXECUTABLE.  Signal
   6549 `user-error', if EXECUTABLE does not denote a command or an
   6550 executable file.
   6551 
   6552 This command is intended for interactive use only.  In Lisp, just
   6553 `let'-bind the corresponding variable, or set it directly.  Use
   6554 `flycheck-checker-executable-variable' to obtain the executable
   6555 variable symbol for a syntax checker."
   6556   (declare (interactive-only "Set the executable variable directly instead"))
   6557   (interactive
   6558    (let* ((checker (flycheck-read-checker "Syntax checker: "))
   6559           (default-executable (flycheck-checker-default-executable checker))
   6560           (executable (if current-prefix-arg
   6561                           nil
   6562                         (read-file-name "Executable: " nil default-executable
   6563                                         nil nil flycheck-executable-find))))
   6564      (list checker executable)))
   6565   (when (and executable (not (funcall flycheck-executable-find executable)))
   6566     (user-error "%s is no executable" executable))
   6567   (let ((variable (flycheck-checker-executable-variable checker)))
   6568     (set (make-local-variable variable) executable)))
   6569 
   6570 
   6571 ;;; Configuration files and options for command checkers
   6572 (defun flycheck-register-config-file-var (var checkers)
   6573   "Register VAR as config file var for CHECKERS.
   6574 
   6575 CHECKERS is a single syntax checker or a list thereof."
   6576   (when (symbolp checkers)
   6577     (setq checkers (list checkers)))
   6578   (dolist (checker checkers)
   6579     (setf (flycheck-checker-get checker 'config-file-var) var)))
   6580 
   6581 ;;;###autoload
   6582 (defmacro flycheck-def-config-file-var (symbol checker &optional file-name
   6583                                                &rest custom-args)
   6584   "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME.
   6585 
   6586 SYMBOL is declared as customizable variable using `defcustom', to
   6587 provide configuration files for the given syntax CHECKER.
   6588 CUSTOM-ARGS are forwarded to `defcustom'.
   6589 
   6590 FILE-NAME is the initial value of the new variable.  If omitted,
   6591 the default value is nil.  It can be either a string or a list of
   6592 strings.
   6593 
   6594 Use this together with the `config-file' form in the `:command'
   6595 argument to `flycheck-define-checker'."
   6596   (declare (indent 3))
   6597   `(progn
   6598      (defcustom ,symbol ,file-name
   6599        ,(format "Configuration file for `%s'.
   6600 
   6601 If set to a string, locate the configuration file using the
   6602 functions from `flycheck-locate-config-file-functions'.  If the
   6603 file is found pass it to the syntax checker as configuration
   6604 file.
   6605 
   6606 If no configuration file is found, or if this variable is set to
   6607 nil, invoke the syntax checker without a configuration file.
   6608 
   6609 Use this variable as file-local variable if you need a specific
   6610 configuration file for a buffer." checker)
   6611        :type '(choice (const :tag "No configuration file" nil)
   6612                       (string :tag "File name or path")
   6613                       (repeat :tag "File names or paths" string))
   6614        :safe #'flycheck-string-or-string-list-p
   6615        :group 'flycheck-config-files
   6616        ,@custom-args)
   6617      (flycheck-register-config-file-var ',symbol ',checker)))
   6618 
   6619 (defun flycheck-locate-config-file (filenames checker)
   6620   "Locate the configuration file for CHECKER, based on FILENAMES.
   6621 
   6622 FILENAMES can be either a single file, or a list.  Each filename
   6623 is passed to all `flycheck-locate-config-file-functions', until
   6624 one returns non-nil.
   6625 
   6626 Return the absolute path of the configuration file, or nil if no
   6627 configuration file was found."
   6628   (when (stringp filenames)
   6629     (setq filenames (list filenames)))
   6630   (let ((config-file nil))
   6631     (while (and filenames (null config-file))
   6632       (setq config-file (run-hook-with-args-until-success
   6633                          'flycheck-locate-config-file-functions
   6634                          (pop filenames) checker)))
   6635     (when (and config-file (file-exists-p config-file))
   6636       config-file)))
   6637 
   6638 (defun flycheck-locate-config-file-by-path (filepath _checker)
   6639   "Locate a configuration file by a FILEPATH.
   6640 
   6641 If FILEPATH is a contains a path separator, expand it against the
   6642 default directory and return it if it points to an existing file.
   6643 Otherwise return nil.
   6644 
   6645 _CHECKER is ignored."
   6646   ;; If the path is just a plain file name, skip it.
   6647   (unless (string= (file-name-nondirectory filepath) filepath)
   6648     (let ((file-name (expand-file-name filepath)))
   6649       (and (file-exists-p file-name) file-name))))
   6650 
   6651 (defun flycheck-locate-config-file-ancestor-directories (filename _checker)
   6652   "Locate a configuration FILENAME in ancestor directories.
   6653 
   6654 If the current buffer has a file name, search FILENAME in the
   6655 directory of the current buffer and all ancestors thereof (see
   6656 `locate-dominating-file').  If the file is found, return its
   6657 absolute path.  Otherwise return nil.
   6658 
   6659 _CHECKER is ignored."
   6660   (when-let* ((basefile (buffer-file-name))
   6661               (directory (locate-dominating-file basefile filename)))
   6662     (expand-file-name filename directory)))
   6663 
   6664 (defun flycheck-locate-config-file-home (filename _checker)
   6665   "Locate a configuration FILENAME in the home directory.
   6666 
   6667 Return the absolute path, if FILENAME exists in the user's home
   6668 directory, or nil otherwise."
   6669   (let ((path (expand-file-name filename "~")))
   6670     (when (file-exists-p path)
   6671       path)))
   6672 
   6673 (seq-do (apply-partially #'custom-add-frequent-value
   6674                          'flycheck-locate-config-file-functions)
   6675         '(flycheck-locate-config-file-by-path
   6676           flycheck-locate-config-file-ancestor-directories
   6677           flycheck-locate-config-file-home))
   6678 
   6679 (defun flycheck-register-option-var (var checkers)
   6680   "Register an option VAR with CHECKERS.
   6681 
   6682 VAR is an option symbol, and CHECKERS a syntax checker symbol or
   6683 a list thereof.  Register VAR with all CHECKERS so that it
   6684 appears in the help output."
   6685   (when (symbolp checkers)
   6686     (setq checkers (list checkers)))
   6687   (dolist (checker checkers)
   6688     (cl-pushnew var (flycheck-checker-get checker 'option-vars))))
   6689 
   6690 ;;;###autoload
   6691 (defmacro flycheck-def-option-var (symbol init-value checkers docstring
   6692                                           &rest custom-args)
   6693   "Define SYMBOL as option variable with INIT-VALUE for CHECKER.
   6694 
   6695 SYMBOL is declared as customizable variable using `defcustom', to
   6696 provide an option for the given syntax CHECKERS (a checker or a
   6697 list of checkers).  INIT-VALUE is the initial value of the
   6698 variable, and DOCSTRING is its docstring.  CUSTOM-ARGS are
   6699 forwarded to `defcustom'.
   6700 
   6701 Use this together with the `option', `option-list' and
   6702 `option-flag' forms in the `:command' argument to
   6703 `flycheck-define-checker'."
   6704   (declare (indent 3)
   6705            (doc-string 4))
   6706   `(progn
   6707      (defcustom ,symbol ,init-value
   6708        ,(concat docstring "
   6709 
   6710 This variable is an option for the following syntax checkers:
   6711 
   6712 "
   6713                 (mapconcat (lambda (c) (format "  - `%s'" c))
   6714                            (if (symbolp checkers) (list checkers) checkers)
   6715                            "\n"))
   6716        :group 'flycheck-options
   6717        ,@custom-args)
   6718      (flycheck-register-option-var ',symbol ',checkers)))
   6719 
   6720 (defun flycheck-option-int (value)
   6721   "Convert an integral option VALUE to a string.
   6722 
   6723 If VALUE is nil, return nil.  Otherwise return VALUE converted to
   6724 a string."
   6725   (and value (number-to-string value)))
   6726 
   6727 (defun flycheck-option-symbol (value)
   6728   "Convert a symbol option VALUE to string.
   6729 
   6730 If VALUE is nil return nil.  Otherwise return VALUE converted to
   6731 a string."
   6732   (and value (symbol-name value)))
   6733 
   6734 (defun flycheck-option-comma-separated-list (value &optional separator filter)
   6735   "Convert VALUE into a list separated by SEPARATOR.
   6736 
   6737 SEPARATOR is a string to separate items in VALUE, defaulting to
   6738 \",\".  FILTER is an optional function, which takes a single
   6739 argument and returns either a string or nil.
   6740 
   6741 If VALUE is a list, apply FILTER to each item in VALUE, remove
   6742 all nil items, and return a single string of all remaining items
   6743 separated by SEPARATOR.
   6744 
   6745 Otherwise, apply FILTER to VALUE and return the result.
   6746 SEPARATOR is ignored in this case."
   6747   (let ((filter (or filter #'identity))
   6748         (separator (or separator ",")))
   6749     (if (listp value)
   6750         (when-let (value (delq nil (seq-map filter value)))
   6751           (string-join value separator))
   6752       (funcall filter value))))
   6753 
   6754 (defmacro flycheck-def-args-var (symbol checkers &rest custom-args)
   6755   "Define SYMBOL as argument variable for CHECKERS.
   6756 
   6757 SYMBOL is declared as customizable, risky and buffer-local
   6758 variable using `defcustom' to provide an option for arbitrary
   6759 arguments for the given syntax CHECKERS (either a single checker
   6760 or a list of checkers).  CUSTOM-ARGS is forwarded to `defcustom'.
   6761 
   6762 Use the `eval' form to splice this variable into the
   6763 `:command'."
   6764   (declare (indent 2))
   6765   `(flycheck-def-option-var ,symbol nil ,checkers
   6766      "A list of additional command line arguments.
   6767 
   6768 The value of this variable is a list of strings with additional
   6769 command line arguments."
   6770      :risky t
   6771      :type '(repeat (string :tag "Argument"))
   6772      ,@custom-args))
   6773 
   6774 
   6775 ;;; Command syntax checkers as compile commands
   6776 (defun flycheck-checker-pattern-to-error-regexp (pattern)
   6777   "Convert PATTERN into an error regexp for compile.el.
   6778 
   6779 Return a list representing PATTERN, suitable as element in
   6780 `compilation-error-regexp-alist'."
   6781   (let* ((regexp (car pattern))
   6782          (level (cdr pattern))
   6783          (level-no (flycheck-error-level-compilation-level level)))
   6784     `(,regexp 1 (2 . 6) (3 . 7) ,level-no)))
   6785 
   6786 (defun flycheck-checker-compilation-error-regexp-alist (checker)
   6787   "Convert error patterns of CHECKER for use with compile.el.
   6788 
   6789 Return an alist of all error patterns of CHECKER, suitable for
   6790 use with `compilation-error-regexp-alist'."
   6791   (seq-map #'flycheck-checker-pattern-to-error-regexp
   6792            (flycheck-checker-get checker 'error-patterns)))
   6793 
   6794 (defun flycheck--substitute-shell-command-argument (arg checker)
   6795   "Substitute ARG for CHECKER.
   6796 
   6797 Like `flycheck-substitute-argument', except for source,
   6798 source-inplace, and source-original."
   6799   (if (memq arg '(source source-inplace source-original))
   6800       (list buffer-file-name)
   6801     (flycheck-substitute-argument arg checker)))
   6802 
   6803 (defun flycheck--checker-substituted-shell-command-arguments (checker)
   6804   "Get the substituted arguments of a CHECKER to run as a shell command.
   6805 
   6806 Substitute each argument of CHECKER using
   6807 `flycheck-substitute-shell-command-argument'."
   6808   (apply #'append
   6809          (seq-map (lambda (arg)
   6810                     (flycheck--substitute-shell-command-argument arg checker))
   6811                   (flycheck-checker-arguments checker))))
   6812 
   6813 (defun flycheck-checker-shell-command (checker)
   6814   "Get a shell command for CHECKER.
   6815 
   6816 Perform substitution in the arguments of CHECKER, but with
   6817 `flycheck--substitute-shell-command-argument'.
   6818 
   6819 Return the command of CHECKER as single string, suitable for
   6820 shell execution."
   6821   ;; Note: Do NOT use `combine-and-quote-strings' here.  Despite it's name it
   6822   ;; does not properly quote shell arguments, and actually breaks for special
   6823   ;; characters.  See https://github.com/flycheck/flycheck/pull/522
   6824   (let* ((args (flycheck--checker-substituted-shell-command-arguments checker))
   6825          (program
   6826           (or (flycheck-find-checker-executable checker)
   6827               (user-error "Cannot find `%s' using `flycheck-executable-find'"
   6828                           (flycheck-checker-executable checker))))
   6829          (wrapped (flycheck--wrap-command program args))
   6830          (abs-prog
   6831           ;; The executable path returned by `flycheck-command-wrapper-function'
   6832           ;; may not be absolute, so expand it here.  See URL
   6833           ;; `https://github.com/flycheck/flycheck/issues/1461'.
   6834           (or (executable-find (car wrapped))
   6835               (user-error "Cannot find `%s' using `executable-find'"
   6836                           (car wrapped))))
   6837          (command (mapconcat #'shell-quote-argument
   6838                              (cons abs-prog (cdr wrapped)) " ")))
   6839     (if (flycheck-checker-get checker 'standard-input)
   6840         ;; If the syntax checker expects the source from standard input add an
   6841         ;; appropriate shell redirection
   6842         (concat command " < " (shell-quote-argument (buffer-file-name)))
   6843       command)))
   6844 
   6845 (defun flycheck-compile-name (_name)
   6846   "Get a name for a Flycheck compilation buffer.
   6847 
   6848 _NAME is ignored."
   6849   (format "*Flycheck %s*" (buffer-file-name)))
   6850 
   6851 (defun flycheck-compile (checker)
   6852   "Run CHECKER via `compile'.
   6853 
   6854 CHECKER must be a valid syntax checker.  Interactively, prompt
   6855 for a syntax checker to run.
   6856 
   6857 Instead of highlighting errors in the buffer, this command pops
   6858 up a separate buffer with the entire output of the syntax checker
   6859 tool, just like `compile' (\\[compile])."
   6860   (interactive
   6861    (let* ((default (flycheck-get-checker-for-buffer))
   6862           (prompt (concat
   6863                    "Run syntax checker as compile command"
   6864                    (when default (concat " [" (format "%S" default) "]"))
   6865                    ": ")))
   6866      (list (flycheck-read-checker prompt
   6867                                   (when (flycheck-checker-get default 'command)
   6868                                     default)
   6869                                   'command))))
   6870   (unless (flycheck-valid-checker-p checker)
   6871     (user-error "%S is not a valid syntax checker" checker))
   6872   (unless (buffer-file-name)
   6873     (user-error "Cannot compile a buffer without a backing file"))
   6874   (unless (flycheck-may-use-checker checker)
   6875     (user-error "Cannot use syntax checker %S in this buffer" checker))
   6876   (unless (flycheck-checker-executable checker)
   6877     (user-error "Cannot run checker %S as shell command" checker))
   6878   (save-some-buffers)
   6879   (let* ((default-directory (flycheck-compute-working-directory checker))
   6880          (command (flycheck-checker-shell-command checker))
   6881          (buffer (compilation-start command nil #'flycheck-compile-name)))
   6882     (with-current-buffer buffer
   6883       (setq-local compilation-error-regexp-alist
   6884                   (flycheck-checker-compilation-error-regexp-alist checker)))))
   6885 
   6886 
   6887 ;;; General error parsing for command checkers
   6888 (defun flycheck-parse-output (output checker buffer)
   6889   "Parse OUTPUT from CHECKER in BUFFER.
   6890 
   6891 OUTPUT is a string with the output from the checker symbol
   6892 CHECKER.  BUFFER is the buffer which was checked.
   6893 
   6894 Return the errors parsed with the error patterns of CHECKER."
   6895   (funcall (flycheck-checker-get checker 'error-parser) output checker buffer))
   6896 
   6897 (defun flycheck-fix-error-filename (err buffer-files cwd)
   6898   "Fix the file name of ERR from BUFFER-FILES.
   6899 
   6900 Resolves error file names relative to CWD directory.
   6901 
   6902 Make the file name of ERR absolute.  If the absolute file name of
   6903 ERR is in BUFFER-FILES, replace it with the value of variable
   6904 `buffer-file-name'."
   6905   (flycheck-error-with-buffer err
   6906     (when-let (filename (flycheck-error-filename err))
   6907       (when (seq-some (apply-partially #'flycheck-same-files-p
   6908                                        (expand-file-name filename cwd))
   6909                       buffer-files)
   6910         (setf (flycheck-error-filename err) buffer-file-name)
   6911         (when (and buffer-file-name (flycheck-error-message err))
   6912           (setf (flycheck-error-message err)
   6913                 (replace-regexp-in-string
   6914                  (regexp-quote filename) buffer-file-name
   6915                  (flycheck-error-message err) 'fixed-case 'literal))))))
   6916   err)
   6917 
   6918 
   6919 ;;; Error parsers for command syntax checkers
   6920 (defun flycheck-parse-xml-region (beg end)
   6921   "Parse the xml region between BEG and END.
   6922 
   6923 Wrapper around `xml-parse-region' which transforms the return
   6924 value of this function into one compatible to
   6925 `libxml-parse-xml-region' by simply returning the first element
   6926 from the node list."
   6927   (ignore-errors (car (xml-parse-region beg end))))
   6928 
   6929 (defun flycheck-parse-xml-region-with-fallback (beg end)
   6930   "Parse the xml region between BEG and END.
   6931 
   6932 Try parsing with libxml first; if that fails, revert to
   6933 `flycheck-parse-xml-region'.  Failures can be caused by incorrect
   6934 XML (see URL `https://github.com/flycheck/flycheck/issues/1298'),
   6935 or on Windows by a missing libxml DLL with a libxml-enabled Emacs
   6936 \(see URL `https://github.com/flycheck/flycheck/issues/1330')."
   6937   ;; FIXME use `libxml-available-p' when it gets implemented.
   6938   (or (and (fboundp 'libxml-parse-xml-region)
   6939            (libxml-parse-xml-region beg end))
   6940       (flycheck-parse-xml-region beg end)))
   6941 
   6942 (defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback
   6943   "Function used to parse an xml string from a region.
   6944 
   6945 The default uses libxml if available, and falls back to
   6946 `flycheck-parse-xml-region' otherwise.")
   6947 
   6948 (defun flycheck-parse-xml-string (xml)
   6949   "Parse an XML string.
   6950 
   6951 Return the document tree parsed from XML in the form `(ROOT ATTRS
   6952 BODY...)'.  ROOT is a symbol identifying the name of the root
   6953 element.  ATTRS is an alist of the attributes of the root node.
   6954 BODY is zero or more body elements, either as strings (in case of
   6955 text nodes) or as XML nodes, in the same for as the root node."
   6956   (with-temp-buffer
   6957     (insert xml)
   6958     (funcall flycheck-xml-parser (point-min) (point-max))))
   6959 
   6960 (defun flycheck-parse-checkstyle (output checker buffer)
   6961   "Parse Checkstyle errors from OUTPUT.
   6962 
   6963 Parse Checkstyle-like XML output.  Use this error parser for
   6964 checkers that have an option to output errors in this format.
   6965 
   6966 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   6967 the BUFFER that was checked respectively.
   6968 
   6969 See URL `https://checkstyle.sourceforge.net/' for information
   6970 about Checkstyle."
   6971   (pcase (flycheck-parse-xml-string output)
   6972     (`(checkstyle ,_ . ,file-nodes)
   6973      (let (errors)
   6974        (dolist (node file-nodes)
   6975          (pcase node
   6976            (`(file ,file-attrs . ,error-nodes)
   6977             (dolist (node error-nodes)
   6978               (pcase node
   6979                 (`(error ,error-attrs . ,_)
   6980                  (let-alist error-attrs
   6981                    (push (flycheck-error-new-at
   6982                           (flycheck-string-to-number-safe .line)
   6983                           (flycheck-string-to-number-safe .column)
   6984                           (pcase .severity
   6985                             (`"error"   'error)
   6986                             (`"warning" 'warning)
   6987                             (`"info"    'info)
   6988                             ;; Default to error for unknown .severity
   6989                             (_          'error))
   6990                           .message
   6991                           :checker checker :id .source
   6992                           :buffer buffer
   6993                           :filename (cdr (assq 'name file-attrs)))
   6994                          errors))))))))
   6995        (nreverse errors)))))
   6996 
   6997 (defun flycheck-parse-cppcheck (output checker buffer)
   6998   "Parse Cppcheck errors from OUTPUT.
   6999 
   7000 Parse Cppcheck XML v2 output.
   7001 
   7002 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7003 the BUFFER that was checked respectively.
   7004 
   7005 See URL `https://cppcheck.sourceforge.net/' for more information
   7006 about Cppcheck."
   7007   (pcase (flycheck-parse-xml-string output)
   7008     (`(results ,_ . ,body)
   7009      (let (errors)
   7010        (dolist (node body)
   7011          (pcase node
   7012            (`(errors ,_ . ,error-nodes)
   7013             (dolist (node error-nodes)
   7014               (pcase node
   7015                 (`(error ,error-attrs . ,loc-nodes)
   7016                  (let ((id (cdr (assq 'id error-attrs)))
   7017                        (message (cdr (assq 'verbose error-attrs)))
   7018                        (level (pcase (cdr (assq 'severity error-attrs))
   7019                                 (`"error" 'error)
   7020                                 (`"style" 'info)
   7021                                 (`"information" 'info)
   7022                                 (_ 'warning))))
   7023                    (dolist (node loc-nodes)
   7024                      (pcase node
   7025                        (`(location ,loc-attrs . ,_)
   7026                         (let-alist loc-attrs
   7027                           (push (flycheck-error-new-at
   7028                                  (flycheck-string-to-number-safe .line)
   7029                                  nil
   7030                                  level
   7031                                  ;; cppcheck return newline characters as "\012"
   7032                                  (replace-regexp-in-string "\\\\012" "\n"
   7033                                                            message)
   7034                                  :id id
   7035                                  :checker checker
   7036                                  :buffer buffer
   7037                                  :filename .file)
   7038                                 errors))))))))))))
   7039        (nreverse errors)))))
   7040 
   7041 (defun flycheck-parse-phpmd (output checker buffer)
   7042   "Parse phpmd errors from OUTPUT.
   7043 
   7044 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7045 the BUFFER that was checked respectively.
   7046 
   7047 See URL `https://phpmd.org/' for more information about phpmd."
   7048   (pcase (flycheck-parse-xml-string output)
   7049     (`(pmd ,_ . ,body)
   7050      (let (errors)
   7051        (dolist (node body)
   7052          (pcase node
   7053            (`(file ,file-attrs . ,violation-nodes)
   7054             (let ((filename (cdr (assq 'name file-attrs))))
   7055               (dolist (node violation-nodes)
   7056                 (pcase node
   7057                   (`(violation ,vio-attrs ,(and message (pred stringp)))
   7058                    (let-alist vio-attrs
   7059                      (push
   7060                       (flycheck-error-new-at
   7061                        (flycheck-string-to-number-safe .beginline)
   7062                        nil
   7063                        'warning (string-trim message)
   7064                        ;; Ignore .endline (phpmd marks giant spans as errors)
   7065                        ;; :end-line (flycheck-string-to-number-safe .endline)
   7066                        :id .rule
   7067                        :checker checker
   7068                        :buffer buffer
   7069                        :filename filename)
   7070                       errors)))))))))
   7071        (nreverse errors)))))
   7072 
   7073 (defun flycheck-parse-reek (output checker buffer)
   7074   "Parse Reek warnings from JSON OUTPUT.
   7075 
   7076 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7077 the BUFFER that was checked respectively.
   7078 
   7079 See URL `https://github.com/troessner/reek' for more information
   7080 about Reek."
   7081   (let ((errors nil))
   7082     (dolist (message (car (flycheck-parse-json output)))
   7083       (let-alist message
   7084         (dolist (line (delete-dups .lines))
   7085           (push
   7086            (flycheck-error-new-at
   7087             line
   7088             nil
   7089             'warning (concat .context " " .message)
   7090             :id .smell_type
   7091             :checker checker
   7092             :buffer buffer
   7093             :filename .source)
   7094            errors))))
   7095     (nreverse errors)))
   7096 
   7097 (defun flycheck-parse-go-staticcheck (output checker buffer)
   7098   "Parse staticheck warnings from JSON OUTPUT.
   7099 
   7100 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7101 the BUFFER that was checked respectively.
   7102 
   7103 See URL `https://staticcheck.io/docs/formatters' for more
   7104 information about staticheck."
   7105   (let ((errors nil))
   7106     (dolist (msg (flycheck-parse-json output))
   7107       (let-alist msg
   7108         (push
   7109          (flycheck-error-new-at
   7110           .location.line
   7111           .location.column
   7112           (pcase .severity
   7113             (`"error"   'error)
   7114             (`"warning" 'warning)
   7115             (`"ignored" 'info)
   7116             ;; Default to warning for unknown .severity
   7117             (_          'warning))
   7118           .message
   7119           :id .code
   7120           :checker checker
   7121           :buffer buffer
   7122           :filename .location.file)
   7123          errors)))
   7124     (nreverse errors)))
   7125 
   7126 (defun flycheck-parse-tslint (output checker buffer)
   7127   "Parse TSLint errors from JSON OUTPUT.
   7128 
   7129 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   7130 the BUFFER that was checked respectively.
   7131 
   7132 See URL `https://palantir.github.io/tslint/' for more information
   7133 about TSLint."
   7134   (seq-map (lambda (message)
   7135              (let-alist message
   7136                (flycheck-error-new-at
   7137                 (+ 1 .startPosition.line)
   7138                 (+ 1 .startPosition.character)
   7139                 (pcase .ruleSeverity
   7140                   ("ERROR"   'error)
   7141                   ("WARNING" 'warning)
   7142                   (_         'warning))
   7143                 .failure
   7144                 :id .ruleName
   7145                 :checker checker
   7146                 :buffer buffer
   7147                 :filename .name
   7148                 :end-line (+ 1 .endPosition.line)
   7149                 :end-column (+ 1 .endPosition.character))))
   7150            (car (flycheck-parse-json output))))
   7151 
   7152 (defun flycheck-parse-rust-collect-spans (span)
   7153   "Return a list of spans contained in a SPAN object."
   7154   (let ((spans))
   7155     (let-alist span
   7156       ;; With macro expansion errors, some spans will point to phony file names
   7157       ;; to indicate an error inside the std rust lib.  We skip these spans as
   7158       ;; they won't appear in flycheck anyway.
   7159       (unless (string= .file_name "<std macros>")
   7160         (push span spans))
   7161 
   7162       ;; Macro expansion errors will have a span in the 'expansion' field, so we
   7163       ;; recursively collect it.
   7164       (if .expansion.span
   7165           (append (flycheck-parse-rust-collect-spans .expansion.span)
   7166                   spans)
   7167         spans))))
   7168 
   7169 (defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer)
   7170   "Turn a rustc DIAGNOSTIC into a `flycheck-error'.
   7171 
   7172 CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC
   7173 and the BUFFER that was checked respectively.
   7174 
   7175 DIAGNOSTIC should be a parsed JSON object describing a rustc
   7176 diagnostic, following the format described there:
   7177 
   7178 https://github.com/rust-lang/rust/blob/master/src/librustc_errors/json.rs#L154"
   7179   (let ((error-message)
   7180         (error-level)
   7181         (error-code)
   7182         (primary-filename)
   7183         (primary-line)
   7184         (primary-column)
   7185         (primary-end-line)
   7186         (primary-end-column)
   7187         (group (make-symbol "group"))
   7188         (spans)
   7189         (children)
   7190         (errors))
   7191     ;; The diagnostic format is described in the link above.  The gist of it is
   7192     ;; that a diagnostic can have several causes in the source text; these
   7193     ;; causes are represented by spans.  The diagnostic has a message and a
   7194     ;; level (error, warning), while the spans have a filename, line, column,
   7195     ;; and an optional label.  The primary span points to the root cause of the
   7196     ;; error in the source text, while non-primary spans point to related
   7197     ;; causes.  Spans may have an 'expansion' field for macro expansion errors;
   7198     ;; these expansion fields will contain another span (and so on).  In
   7199     ;; addition, a diagnostic can also have children diagnostics that are used
   7200     ;; to provide additional information through their message field, but do not
   7201     ;; seem to contain any spans (yet).
   7202     ;;
   7203     ;; We first gather spans in order to turn every span into a flycheck error
   7204     ;; object, that we collect into the `errors' list.
   7205 
   7206     ;; Nested `let-alist' cause compilation warnings, hence we `setq' all
   7207     ;; these values here first to avoid nesting.
   7208     (let-alist diagnostic
   7209       (setq error-message .message
   7210             error-level (pcase .level
   7211                           (`"error" 'error)
   7212                           (`"warning" 'warning)
   7213                           (`"note" 'info)
   7214                           (_ 'error))
   7215             ;; The 'code' field of the diagnostic contains the actual error
   7216             ;; code and an optional explanation that we ignore
   7217             error-code .code.code
   7218             ;; Collect all spans recursively
   7219             spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans)
   7220             children .children))
   7221 
   7222     ;; Turn each span into a flycheck error
   7223     (dolist (span spans)
   7224       (let-alist span
   7225         ;; Children may not have filename/line/column information, so we use
   7226         ;; those from the primary span
   7227         (when .is_primary
   7228           (setq primary-filename .file_name
   7229                 primary-line .line_start
   7230                 primary-column .column_start
   7231                 primary-end-line .line_end
   7232                 primary-end-column .column_end))
   7233         (push
   7234          (flycheck-error-new-at
   7235           .line_start
   7236           .column_start
   7237           ;; Non-primary spans are used for notes
   7238           (if .is_primary error-level 'info)
   7239           (if .is_primary
   7240               ;; Primary spans may have labels with additional information
   7241               (concat error-message (when .label
   7242                                       (format " (%s)" .label)))
   7243             ;; If the label is empty, fallback on the error message,
   7244             ;; otherwise we won't be able to display anything
   7245             (or .label error-message))
   7246           :id error-code
   7247           :checker checker
   7248           :buffer buffer
   7249           :filename .file_name
   7250           :group group
   7251           :end-line .line_end
   7252           :end-column .column_end)
   7253          errors)))
   7254 
   7255     ;; Then we turn children messages into flycheck errors pointing to the
   7256     ;; location of the primary span.
   7257     (dolist (child children)
   7258       (let ((message (let-alist child .message)))
   7259         (let-alist (car (let-alist child .spans))
   7260           (push
   7261            (flycheck-error-new-at
   7262             ;; Use the line/column from the first span if there is one, or
   7263             ;; fallback to the line/column information from the primary span of
   7264             ;; the diagnostic.
   7265             (or .line_start primary-line)
   7266             (or .column_start primary-column)
   7267             'info
   7268             ;; Messages from `cargo clippy' may suggest replacement code.  In
   7269             ;; these cases, the `message' field itself is an unhelpful `try' or
   7270             ;; `change this to'.  We add the `suggested_replacement' field in
   7271             ;; these cases.
   7272             (if .suggested_replacement
   7273                 (format "%s: `%s`" message .suggested_replacement)
   7274               message)
   7275             :id error-code
   7276             :checker checker
   7277             :buffer buffer
   7278             :filename primary-filename
   7279             :group group
   7280             :end-line (or .line_end primary-end-line)
   7281             :end-column (or .column_end primary-end-column))
   7282            errors))))
   7283 
   7284     ;; If there are no spans, the error is not associated with a specific
   7285     ;; file but with the project as a whole.  We still need to report it to
   7286     ;; the user by emitting a corresponding flycheck-error object.
   7287     ;; Check whether the code is non-nil because Rust≥1.44 includes the
   7288     ;; warning count upon completion.
   7289     (when (and error-code (not spans))
   7290       (push (flycheck-error-new-at
   7291              ;; We have no specific position to attach the error to, so
   7292              ;; let's use the top of the file.
   7293              1 1
   7294              error-level
   7295              error-message
   7296              :id error-code
   7297              :checker checker
   7298              :buffer buffer
   7299              :group group)
   7300             errors))
   7301     (nreverse errors)))
   7302 
   7303 (defconst flycheck--json-parser
   7304   (if (and (functionp 'json-parse-buffer)
   7305            ;; json-parse-buffer only supports keyword arguments in Emacs 27+
   7306            (>= emacs-major-version 27))
   7307       (lambda ()
   7308         (json-parse-buffer
   7309          :object-type 'alist :array-type 'list
   7310          :null-object nil :false-object nil))
   7311     #'json-read)
   7312   "Function to use to parse JSON strings.")
   7313 
   7314 (defun flycheck-parse-json (output)
   7315   "Return parsed JSON data from OUTPUT.
   7316 
   7317 OUTPUT is a string that contains JSON data.  Each line of OUTPUT
   7318 may be either plain text, a JSON array (starting with `['), or a
   7319 JSON object (starting with `{').
   7320 
   7321 This function ignores the plain text lines, parses the JSON
   7322 lines, and returns the parsed JSON lines in a list."
   7323   (let ((objects nil)
   7324         (json-array-type 'list)
   7325         (json-false nil))
   7326     (with-temp-buffer
   7327       (insert output)
   7328       (goto-char (point-min))
   7329       (while (not (eobp))
   7330         (when (memq (char-after) '(?\{ ?\[))
   7331           (push (funcall flycheck--json-parser) objects))
   7332         (forward-line)))
   7333     (nreverse objects)))
   7334 
   7335 (defun flycheck-parse-rustc (output checker buffer)
   7336   "Parse rustc errors from OUTPUT and return a list of `flycheck-error'.
   7337 
   7338 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7339 the BUFFER that was checked respectively.
   7340 
   7341 The expected format for OUTPUT is a mix of plain text lines and
   7342 JSON lines.  This function ignores the plain text lines and
   7343 parses only JSON lines.  Each JSON line is expected to be a JSON
   7344 object that corresponds to a diagnostic from the compiler.  The
   7345 expected diagnostic format is described there:
   7346 
   7347 https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139"
   7348   (seq-mapcat (lambda (msg)
   7349                 (flycheck-parse-rustc-diagnostic msg checker buffer))
   7350               (flycheck-parse-json output)))
   7351 
   7352 (defun flycheck-parse-cargo-rustc (output checker buffer)
   7353   "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'.
   7354 
   7355 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   7356 the BUFFER that was checked respectively.
   7357 
   7358 The expected format for OUTPUT is a mix of plain text lines and
   7359 JSON lines.  This function ignores the plain text lines and
   7360 parses only JSON lines.  Each JSON line is expected to be a JSON
   7361 object that represents a message from Cargo.  The format of
   7362 messages emitted by Cargo is described in cargo's
   7363 machine_message.rs at URL `https://git.io/vh24R'."
   7364   (let ((errors))
   7365     (dolist (msg (flycheck-parse-json output))
   7366       (let-alist msg
   7367         ;; Errors and warnings from rustc are wrapped by cargo, so we filter and
   7368         ;; unwrap them, and delegate the actual construction of `flycheck-error'
   7369         ;; objects to `flycheck-parse-rustc-diagnostic'.
   7370         ;; We put the error record with nil code since flycheck regards
   7371         ;; the case of nonzero return code without any error report
   7372         ;; as abnormal result.
   7373         (when (string= .reason "compiler-message")
   7374           (push (flycheck-parse-rustc-diagnostic .message checker buffer)
   7375                 errors))))
   7376     (apply #'nconc errors)))
   7377 
   7378 ;; Some checkers output ANSI terminal colors, which don't match up
   7379 ;; with :error-patterns, so we strip those color codes from the output
   7380 ;; here before passing it along to the default behavior. This is
   7381 ;; originally only used in the rebar3 checker, but the systemd checker
   7382 ;; now also makes use of it.
   7383 ;;
   7384 ;; The relevant discussion can be found at
   7385 ;; https://github.com/flycheck/flycheck/pull/1144
   7386 (defun flycheck-parse-with-patterns-without-color (output checker buffer)
   7387   "Strip color codes from OUTPUT before passing it to the default behavior.
   7388 
   7389 CHECKER and BUFFER are passed along as well."
   7390   (flycheck-parse-with-patterns
   7391    (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
   7392    checker buffer))
   7393 
   7394 
   7395 ;;; Error parsing with regular expressions
   7396 (defun flycheck-get-regexp (patterns)
   7397   "Create a single regular expression from PATTERNS."
   7398   (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns))
   7399                 'no-group))
   7400 
   7401 (defun flycheck-tokenize-output-with-patterns (output patterns)
   7402   "Tokenize OUTPUT with PATTERNS.
   7403 
   7404 Split the output into error tokens, using all regular expressions
   7405 from the error PATTERNS.  An error token is simply a string
   7406 containing a single error from OUTPUT.  Such a token can then be
   7407 parsed into a structured error by applying the PATTERNS again,
   7408 see `flycheck-parse-error-with-patterns'.
   7409 
   7410 Return a list of error tokens."
   7411   (let ((regexp (flycheck-get-regexp patterns))
   7412         (last-match 0)
   7413         errors)
   7414     (while (string-match regexp output last-match)
   7415       (push (match-string 0 output) errors)
   7416       (setq last-match (match-end 0)))
   7417     (reverse errors)))
   7418 
   7419 (defun flycheck-try-parse-error-with-pattern (err pattern checker)
   7420   "Try to parse a single ERR with a PATTERN for CHECKER.
   7421 
   7422 Return the parsed error if PATTERN matched ERR, or nil
   7423 otherwise.
   7424 
   7425 `end-line' defaults to the value of `line' when `end-column' is
   7426 set, since checkers often omit redundant end lines (as in
   7427 <file>:<line>:<column>-<end-column>)."
   7428   (let ((regexp (car pattern))
   7429         (level (cdr pattern)))
   7430     (when (string-match regexp err)
   7431       (let ((filename (match-string 1 err))
   7432             (line (flycheck-string-to-number-safe (match-string 2 err)))
   7433             (column (flycheck-string-to-number-safe (match-string 3 err)))
   7434             (message (match-string 4 err))
   7435             (id (match-string 5 err))
   7436             (end-line (flycheck-string-to-number-safe (match-string 6 err)))
   7437             (end-column (flycheck-string-to-number-safe (match-string 7 err))))
   7438         (flycheck-error-new-at
   7439          line
   7440          column
   7441          level
   7442          (unless (string-empty-p message) message)
   7443          :id (unless (string-empty-p id) id)
   7444          :checker checker
   7445          :filename (if (or (null filename) (string-empty-p filename))
   7446                        (buffer-file-name)
   7447                      filename)
   7448          :end-line (or end-line (and end-column line))
   7449          :end-column end-column)))))
   7450 
   7451 (defun flycheck-parse-error-with-patterns (err patterns checker)
   7452   "Parse a single ERR with error PATTERNS for CHECKER.
   7453 
   7454 Apply each pattern in PATTERNS to ERR, in the given order, and
   7455 return the first parsed error."
   7456   ;; Try to parse patterns in the order of declaration to make sure that the
   7457   ;; first match wins.
   7458   (let (parsed-error)
   7459     (while (and patterns
   7460                 (not (setq parsed-error
   7461                            (flycheck-try-parse-error-with-pattern
   7462                             err (car patterns) checker))))
   7463       (setq patterns (cdr patterns)))
   7464     parsed-error))
   7465 
   7466 (defun flycheck-parse-with-patterns (output checker buffer)
   7467   "Parse OUTPUT from CHECKER with error patterns.
   7468 
   7469 Uses the error patterns of CHECKER to tokenize the output and
   7470 tries to parse each error token with all patterns, in the order
   7471 of declaration.  Hence an error is never matched twice by two
   7472 different patterns.  The pattern declared first always wins.
   7473 
   7474 _BUFFER is ignored.
   7475 
   7476 Return a list of parsed errors and warnings (as `flycheck-error'
   7477 objects)."
   7478   (with-current-buffer buffer
   7479     (let ((patterns (flycheck-checker-get checker 'error-patterns)))
   7480       (seq-map (lambda (err)
   7481                  (flycheck-parse-error-with-patterns err patterns checker))
   7482                (flycheck-tokenize-output-with-patterns output patterns)))))
   7483 
   7484 
   7485 ;;; Convenience definition of command-syntax checkers
   7486 
   7487 ;; This macro is autoloaded to prevent `with-eval-after-load' from expanding its
   7488 ;; arguments.  See https://github.com/flycheck/flycheck/issues/1398.
   7489 ;;;###autoload
   7490 (defmacro flycheck-define-checker (symbol docstring &rest properties)
   7491   "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES.
   7492 
   7493 Like `flycheck-define-command-checker', but PROPERTIES must not
   7494 be quoted.  Also, implicitly define the executable variable for
   7495 SYMBOL with `flycheck-def-executable-var'."
   7496   (declare (indent 1)
   7497            (doc-string 2))
   7498   (let ((command (plist-get properties :command))
   7499         (parser (plist-get properties :error-parser))
   7500         (filter (plist-get properties :error-filter))
   7501         (explainer (plist-get properties :error-explainer))
   7502         (predicate (plist-get properties :predicate))
   7503         (enabled-fn (plist-get properties :enabled))
   7504         (verify-fn (plist-get properties :verify)))
   7505 
   7506     `(progn
   7507        (flycheck-def-executable-var ,symbol ,(car command))
   7508 
   7509        (flycheck-define-command-checker ',symbol
   7510          ,docstring
   7511          :command ',command
   7512          ,@(when parser
   7513              `(:error-parser #',parser))
   7514          :error-patterns ',(plist-get properties :error-patterns)
   7515          ,@(when filter
   7516              `(:error-filter #',filter))
   7517          ,@(when explainer
   7518              `(:error-explainer #',explainer))
   7519          :modes ',(plist-get properties :modes)
   7520          ,@(when predicate
   7521              `(:predicate #',predicate))
   7522          :next-checkers ',(plist-get properties :next-checkers)
   7523          ,@(when enabled-fn
   7524              `(:enabled #',enabled-fn))
   7525          ,@(when verify-fn
   7526              `(:verify #',verify-fn))
   7527          :standard-input ',(plist-get properties :standard-input)
   7528          :working-directory ',(plist-get properties :working-directory)))))
   7529 
   7530 
   7531 ;;; Built-in checkers
   7532 (flycheck-def-args-var flycheck-gnat-args ada-gnat
   7533   :package-version '(flycheck . "0.20"))
   7534 
   7535 (flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat
   7536   "A list of include directories for GNAT.
   7537 
   7538 The value of this variable is a list of strings, where each
   7539 string is a directory to add to the include path of gcc.
   7540 Relative paths are relative to the file being checked."
   7541   :type '(repeat (directory :tag "Include directory"))
   7542   :safe #'flycheck-string-list-p
   7543   :package-version '(flycheck . "0.20"))
   7544 
   7545 (flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat
   7546   "The language standard to use in GNAT.
   7547 
   7548 The value of this variable is either a string denoting a language
   7549 standard, or nil, to use the default standard. When non-nil, pass
   7550 the language standard via the `-std' option."
   7551   :type '(choice (const :tag "Default standard" nil)
   7552                  (string :tag "Language standard"))
   7553   :safe #'flycheck-string-or-nil-p
   7554   :package-version '(flycheck . "0.20"))
   7555 
   7556 (flycheck-def-option-var flycheck-gnat-warnings
   7557     '("wa") ada-gnat
   7558   "A list of additional Ada warnings to enable in GNAT.
   7559 
   7560 The value of this variable is a list of strings, where each
   7561 string is the name of a warning category to enable. By default,
   7562 most optional warnings are recommended, as in `-gnata'.
   7563 
   7564 Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for
   7565 more information about GNAT warnings."
   7566   :type '(repeat :tag "Warnings" (string :tag "Warning name"))
   7567   :safe #'flycheck-string-list-p
   7568   :package-version '(flycheck . "0.20"))
   7569 
   7570 (flycheck-define-checker ada-gnat
   7571   "An Ada syntax checker using GNAT.
   7572 
   7573 Uses the GNAT compiler from GCC.  See URL
   7574 `https://www.adacore.com/community/'."
   7575   :command ("gnatmake"
   7576             "-c"                        ; Just compile, don't bind
   7577             "-f"                        ; Force re-compilation
   7578             "-u"                        ; Compile the main file only
   7579             "-gnatf"                    ; Full error information
   7580             "-gnatef"                   ; Full source file name
   7581             "-D" temporary-directory
   7582             (option-list "-gnat" flycheck-gnat-warnings concat)
   7583             (option-list "-I" flycheck-gnat-include-path concat)
   7584             (option "-gnat" flycheck-gnat-language-standard concat)
   7585             (eval flycheck-gnat-args)
   7586             source)
   7587   :error-patterns
   7588   ((error line-start
   7589           (message "In file included from") " " (file-name) ":" line ":"
   7590           column ":"
   7591           line-end)
   7592    (info line-start (file-name) ":" line ":" column
   7593          ": note: " (message) line-end)
   7594    (warning line-start (file-name) ":" line ":" column
   7595             ": warning: " (message) line-end)
   7596    ;; no specific error prefix in Ada
   7597    (error line-start (file-name) ":" line ":" column
   7598           ": " (message) line-end))
   7599   :modes ada-mode)
   7600 
   7601 (flycheck-define-checker asciidoc
   7602   "A AsciiDoc syntax checker using the AsciiDoc compiler.
   7603 
   7604 See URL `https://www.methods.co.nz/asciidoc'."
   7605   :command ("asciidoc" "-o" null-device "-")
   7606   :standard-input t
   7607   :error-patterns
   7608   ((error line-start
   7609           "asciidoc: ERROR: <stdin>: Line " line ": " (message)
   7610           line-end)
   7611    (warning line-start
   7612             "asciidoc: WARNING: <stdin>: Line " line ": " (message)
   7613             line-end)
   7614    (info line-start
   7615          "asciidoc: DEPRECATED: <stdin>: Line " line ": " (message)
   7616          line-end))
   7617   :modes adoc-mode)
   7618 
   7619 (flycheck-define-checker asciidoctor
   7620   "An AsciiDoc syntax checker using the Asciidoctor compiler.
   7621 
   7622 See URL `https://asciidoctor.org'."
   7623   :command ("asciidoctor" "-o" null-device "-")
   7624   :standard-input t
   7625   :error-patterns
   7626   ((error line-start
   7627           "asciidoctor: ERROR: <stdin>: Line " line ": " (message)
   7628           line-end)
   7629    (warning line-start
   7630             "asciidoctor: WARNING: <stdin>: Line " line ": " (message)
   7631             line-end))
   7632   :modes adoc-mode)
   7633 
   7634 (defun flycheck-awk-gawk-fix-message (err)
   7635   "Remove the repeated file-name/line from the error message of ERR."
   7636   (setf (flycheck-error-message err)
   7637         (replace-regexp-in-string
   7638          (rx line-start
   7639              (group (zero-or-more (any " " "\t")))
   7640              (group (zero-or-more nonl) "\n")
   7641              (backref 1))
   7642          "\\2"
   7643          (replace-regexp-in-string
   7644           (rx "\ngawk: " (zero-or-more (not (any " "))) ":")
   7645           "\n"
   7646           (flycheck-error-message err))))
   7647   err)
   7648 
   7649 (defun flycheck-awk-gawk-error-filter (errors)
   7650   "Remove repeated file-name/line from ERRORS."
   7651   (seq-do #'flycheck-awk-gawk-fix-message errors)
   7652   errors)
   7653 
   7654 (flycheck-define-checker awk-gawk
   7655   "GNU awk's built-in --lint checker."
   7656   :command ("gawk"
   7657             ;; Avoid code execution.  See https://github.com/w0rp/ale/pull/1411
   7658             "--source" "'BEGIN{exit} END{exit 1}'"
   7659             "-f" source
   7660             "--lint"
   7661             "/dev/null")
   7662   :standard-input nil
   7663   :error-patterns
   7664   ((warning line-start
   7665             "gawk: "
   7666             (file-name) ":" line ":" (optional column ":")
   7667             (message (one-or-more not-newline)
   7668                      (optional "\n"
   7669                                (one-or-more not-newline)
   7670                                " ^ "
   7671                                (one-or-more not-newline)))
   7672             line-end))
   7673   :error-filter flycheck-awk-gawk-error-filter
   7674   :modes awk-mode)
   7675 
   7676 (flycheck-define-checker bazel-build-buildifier
   7677   "A checker for Bazel BUILD and BUILD.bazel files using buildifier.
   7678 
   7679 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7680   :command ("buildifier" "-lint=warn" "--type=build")
   7681   :standard-input t
   7682   :error-patterns
   7683   ((error line-start
   7684           "<stdin>:" line ":" column ": " (message)
   7685           line-end)
   7686    (warning line-start
   7687             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7688             line-end))
   7689   :modes bazel-build-mode)
   7690 
   7691 (flycheck-define-checker bazel-module-buildifier
   7692   "A checker for Bazel MODULE.bazel files using buildifier.
   7693 
   7694 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7695   :command ("buildifier" "-lint=warn" "--type=default")
   7696   :standard-input t
   7697   :error-patterns
   7698   ((error line-start
   7699           "<stdin>:" line ":" column ": " (message)
   7700           line-end)
   7701    (warning line-start
   7702             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7703             line-end))
   7704   :modes bazel-module-mode)
   7705 
   7706 (flycheck-define-checker bazel-starlark-buildifier
   7707   "A checker for Starlark bzl files using buildifier.
   7708 
   7709 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7710   :command ("buildifier" "-lint=warn" "--type=bzl")
   7711   :standard-input t
   7712   :error-patterns
   7713   ((error line-start
   7714           "<stdin>:" line ":" column ": " (message)
   7715           line-end)
   7716    (warning line-start
   7717             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7718             line-end))
   7719   :modes bazel-starlark-mode)
   7720 
   7721 (flycheck-define-checker bazel-workspace-buildifier
   7722   "A checker for Bazel WORKSPACE and WORKSPACE.bazel files using buildifier.
   7723 
   7724 See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'."
   7725   :command ("buildifier" "-lint=warn" "--type=workspace")
   7726   :standard-input t
   7727   :error-patterns
   7728   ((error line-start
   7729           "<stdin>:" line ":" column ": " (message)
   7730           line-end)
   7731    (warning line-start
   7732             "<stdin>:" line ": " (id (one-or-more (in word "-"))) ": " (message)
   7733             line-end))
   7734   :modes bazel-workspace-mode)
   7735 
   7736 (flycheck-def-args-var flycheck-clang-args c/c++-clang
   7737   :package-version '(flycheck . "0.22"))
   7738 
   7739 (flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang
   7740   "Enable blocks in Clang.
   7741 
   7742 When non-nil, enable blocks in Clang with `-fblocks'.  See URL
   7743 `https://clang.llvm.org/docs/BlockLanguageSpec.html' for more
   7744 information about blocks."
   7745   :type 'boolean
   7746   :safe #'booleanp
   7747   :package-version '(flycheck . "0.20"))
   7748 
   7749 (flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang
   7750   "Additional preprocessor definitions for Clang.
   7751 
   7752 The value of this variable is a list of strings, where each
   7753 string is an additional definition to pass to Clang, via the `-D'
   7754 option."
   7755   :type '(repeat (string :tag "Definition"))
   7756   :safe #'flycheck-string-list-p
   7757   :package-version '(flycheck . "0.15"))
   7758 
   7759 (flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang
   7760   "A list of include directories for Clang.
   7761 
   7762 The value of this variable is a list of strings, where each
   7763 string is a directory to add to the include path of Clang.
   7764 Relative paths are relative to the file being checked."
   7765   :type '(repeat (directory :tag "Include directory"))
   7766   :safe #'flycheck-string-list-p
   7767   :package-version '(flycheck . "0.14"))
   7768 
   7769 (flycheck-def-option-var flycheck-clang-includes nil c/c++-clang
   7770   "A list of additional include files for Clang.
   7771 
   7772 The value of this variable is a list of strings, where each
   7773 string is a file to include before syntax checking.  Relative
   7774 paths are relative to the file being checked."
   7775   :type '(repeat (file :tag "Include file"))
   7776   :safe #'flycheck-string-list-p
   7777   :package-version '(flycheck . "0.15"))
   7778 
   7779 (flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang
   7780   "The language standard to use in Clang.
   7781 
   7782 The value of this variable is either a string denoting a language
   7783 standard, or nil, to use the default standard.  When non-nil,
   7784 pass the language standard via the `-std' option."
   7785   :type '(choice (const :tag "Default standard" nil)
   7786                  (string :tag "Language standard"))
   7787   :safe #'flycheck-string-or-nil-p
   7788   :package-version '(flycheck . "0.15"))
   7789 (make-variable-buffer-local 'flycheck-clang-language-standard)
   7790 
   7791 (flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang
   7792   "Whether to enable Microsoft extensions to C/C++ in Clang.
   7793 
   7794 When non-nil, enable Microsoft extensions to C/C++ via
   7795 `-fms-extensions'."
   7796   :type 'boolean
   7797   :safe #'booleanp
   7798   :package-version '(flycheck . "0.16"))
   7799 
   7800 (flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang
   7801   "Whether to disable exceptions in Clang.
   7802 
   7803 When non-nil, disable exceptions for syntax checks, via
   7804 `-fno-exceptions'."
   7805   :type 'boolean
   7806   :safe #'booleanp
   7807   :package-version '(flycheck . "0.20"))
   7808 
   7809 (flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang
   7810   "Whether to disable RTTI in Clang.
   7811 
   7812 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
   7813   :type 'boolean
   7814   :safe #'booleanp
   7815   :package-version '(flycheck . "0.15"))
   7816 
   7817 (flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang
   7818   "Whether to warn about language extensions in Clang.
   7819 
   7820 For ISO C, follows the version specified by any -std option used.
   7821 When non-nil, disable non-ISO extensions to C/C++ via
   7822 `-pedantic'."
   7823   :type 'boolean
   7824   :safe #'booleanp
   7825   :package-version '(flycheck . "0.23"))
   7826 
   7827 (flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang
   7828   "Whether to error on language extensions in Clang.
   7829 
   7830 For ISO C, follows the version specified by any -std option used.
   7831 When non-nil, disable non-ISO extensions to C/C++ via
   7832 `-pedantic-errors'."
   7833   :type 'boolean
   7834   :safe #'booleanp
   7835   :package-version '(flycheck . "0.23"))
   7836 
   7837 (flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang
   7838   "The standard library to use for Clang.
   7839 
   7840 The value of this variable is the name of a standard library as
   7841 string, or nil to use the default standard library.
   7842 
   7843 Refer to the Clang manual at URL
   7844 `https://clang.llvm.org/docs/UsersManual.html' for more
   7845 information about the standard library."
   7846   :type '(choice (const :tag "Default standard library" nil)
   7847                  (const "libc++")
   7848                  (const :tag "GNU libstdc++" "libstdc++")
   7849                  (string :tag "Library name"))
   7850   :safe #'flycheck-string-or-nil-p
   7851   :package-version '(flycheck . "0.15"))
   7852 
   7853 (flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang
   7854   "A list of additional warnings to enable in Clang.
   7855 
   7856 The value of this variable is a list of strings, where each string
   7857 is the name of a warning category to enable.  By default, all
   7858 recommended warnings and some extra warnings are enabled (as by
   7859 `-Wall' and `-Wextra' respectively).
   7860 
   7861 Refer to the Clang manual at URL
   7862 `https://clang.llvm.org/docs/UsersManual.html' for more
   7863 information about warnings."
   7864   :type '(choice (const :tag "No additional warnings" nil)
   7865                  (repeat :tag "Additional warnings"
   7866                          (string :tag "Warning name")))
   7867   :safe #'flycheck-string-list-p
   7868   :package-version '(flycheck . "0.14"))
   7869 
   7870 (defun flycheck-c/c++-quoted-include-directory ()
   7871   "Get the directory for quoted includes.
   7872 
   7873 C/C++ compilers typically look up includes with quotation marks
   7874 in the directory of the file being compiled.  However, since
   7875 Flycheck uses temporary copies for syntax checking, it needs to
   7876 explicitly determine the directory for quoted includes.
   7877 
   7878 This function determines the directory by looking at function
   7879 `buffer-file-name', or if that is nil, at `default-directory'."
   7880   (if-let (fn (buffer-file-name))
   7881       (file-name-directory fn)
   7882     ;; If the buffer has no file name, fall back to its default directory
   7883     default-directory))
   7884 
   7885 (flycheck-define-checker c/c++-clang
   7886   "A C/C++ syntax checker using Clang.
   7887 
   7888 See URL `https://clang.llvm.org/'."
   7889   :command ("clang"
   7890             "-fsyntax-only"
   7891             "-fno-color-diagnostics"    ; Do not include color codes in output
   7892             "-fno-caret-diagnostics"    ; Do not visually indicate the source
   7893                                         ; location
   7894             "-fno-diagnostics-show-option" ; Do not show the corresponding
   7895                                         ; warning group
   7896             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   7897             (option "-std=" flycheck-clang-language-standard concat)
   7898             (option-flag "-pedantic" flycheck-clang-pedantic)
   7899             (option-flag "-pedantic-errors" flycheck-clang-pedantic-errors)
   7900             (option "-stdlib=" flycheck-clang-standard-library concat)
   7901             (option-flag "-fms-extensions" flycheck-clang-ms-extensions)
   7902             (option-flag "-fno-exceptions" flycheck-clang-no-exceptions)
   7903             (option-flag "-fno-rtti" flycheck-clang-no-rtti)
   7904             (option-flag "-fblocks" flycheck-clang-blocks)
   7905             (option-list "-include" flycheck-clang-includes)
   7906             (option-list "-W" flycheck-clang-warnings concat)
   7907             (option-list "-D" flycheck-clang-definitions concat)
   7908             (option-list "-I" flycheck-clang-include-path)
   7909             (eval flycheck-clang-args)
   7910             "-x" (eval
   7911                   (pcase major-mode
   7912                     ((or `c++-mode `c++-ts-mode) "c++")
   7913                     ((or `c-mode `c-ts-mode) "c")))
   7914             ;; Read from standard input
   7915             "-")
   7916   :standard-input t
   7917   :error-patterns
   7918   ((info line-start (or "<stdin>" (file-name)) ":" line ":" column
   7919          ": note: " (optional (message)) line-end)
   7920    (warning line-start (or "<stdin>" (file-name)) ":" line ":" column
   7921             ": warning: " (optional (message)) line-end)
   7922    (error line-start (or "<stdin>" (file-name)) ":" line ":" column
   7923           ": " (or "fatal error" "error") ": " (optional (message)) line-end))
   7924   :error-filter
   7925   (lambda (errors)
   7926     (let ((errors (flycheck-sanitize-errors errors)))
   7927       (dolist (err errors)
   7928         ;; Clang will output empty messages for #error/#warning pragmas without
   7929         ;; messages.  We fill these empty errors with a dummy message to get
   7930         ;; them past our error filtering
   7931         (setf (flycheck-error-message err)
   7932               (or (flycheck-error-message err) "no message")))
   7933       errors))
   7934   :modes (c-mode c++-mode c-ts-mode c++-ts-mode)
   7935   :next-checkers ((warning . c/c++-cppcheck)))
   7936 
   7937 (flycheck-def-args-var flycheck-gcc-args c/c++-gcc
   7938   :package-version '(flycheck . "0.22"))
   7939 
   7940 (flycheck-def-option-var flycheck-gcc-definitions nil c/c++-gcc
   7941   "Additional preprocessor definitions for GCC.
   7942 
   7943 The value of this variable is a list of strings, where each
   7944 string is an additional definition to pass to GCC, via the `-D'
   7945 option."
   7946   :type '(repeat (string :tag "Definition"))
   7947   :safe #'flycheck-string-list-p
   7948   :package-version '(flycheck . "0.20"))
   7949 
   7950 (flycheck-def-option-var flycheck-gcc-include-path nil c/c++-gcc
   7951   "A list of include directories for GCC.
   7952 
   7953 The value of this variable is a list of strings, where each
   7954 string is a directory to add to the include path of gcc.
   7955 Relative paths are relative to the file being checked."
   7956   :type '(repeat (directory :tag "Include directory"))
   7957   :safe #'flycheck-string-list-p
   7958   :package-version '(flycheck . "0.20"))
   7959 
   7960 (flycheck-def-option-var flycheck-gcc-includes nil c/c++-gcc
   7961   "A list of additional include files for GCC.
   7962 
   7963 The value of this variable is a list of strings, where each
   7964 string is a file to include before syntax checking.  Relative
   7965 paths are relative to the file being checked."
   7966   :type '(repeat (file :tag "Include file"))
   7967   :safe #'flycheck-string-list-p
   7968   :package-version '(flycheck . "0.20"))
   7969 
   7970 (flycheck-def-option-var flycheck-gcc-language-standard nil c/c++-gcc
   7971   "The language standard to use in GCC.
   7972 
   7973 The value of this variable is either a string denoting a language
   7974 standard, or nil, to use the default standard.  When non-nil,
   7975 pass the language standard via the `-std' option."
   7976   :type '(choice (const :tag "Default standard" nil)
   7977                  (string :tag "Language standard"))
   7978   :safe #'flycheck-string-or-nil-p
   7979   :package-version '(flycheck . "0.20"))
   7980 (make-variable-buffer-local 'flycheck-gcc-language-standard)
   7981 
   7982 (flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc
   7983   "Whether to disable exceptions in GCC.
   7984 
   7985 When non-nil, disable exceptions for syntax checks, via
   7986 `-fno-exceptions'."
   7987   :type 'boolean
   7988   :safe #'booleanp
   7989   :package-version '(flycheck . "0.20"))
   7990 
   7991 (flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc
   7992   "Whether to disable RTTI in GCC.
   7993 
   7994 When non-nil, disable RTTI for syntax checks, via `-fno-rtti'."
   7995   :type 'boolean
   7996   :safe #'booleanp
   7997   :package-version '(flycheck . "0.20"))
   7998 
   7999 (flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc
   8000   "Whether to enable OpenMP in GCC.
   8001 
   8002 When non-nil, enable OpenMP for syntax checkers, via
   8003 `-fopenmp'."
   8004   :type 'boolean
   8005   :safe #'booleanp
   8006   :package-version '(flycheck . "0.21"))
   8007 
   8008 (flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc
   8009   "Whether to warn about language extensions in GCC.
   8010 
   8011 For ISO C, follows the version specified by any -std option used.
   8012 When non-nil, disable non-ISO extensions to C/C++ via
   8013 `-pedantic'."
   8014   :type 'boolean
   8015   :safe #'booleanp
   8016   :package-version '(flycheck . "0.23"))
   8017 
   8018 (flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc
   8019   "Whether to error on language extensions in GCC.
   8020 
   8021 For ISO C, follows the version specified by any -std option used.
   8022 When non-nil, disable non-ISO extensions to C/C++ via
   8023 `-pedantic-errors'."
   8024   :type 'boolean
   8025   :safe #'booleanp
   8026   :package-version '(flycheck . "0.23"))
   8027 
   8028 (flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc
   8029   "A list of additional warnings to enable in GCC.
   8030 
   8031 The value of this variable is a list of strings, where each string
   8032 is the name of a warning category to enable.  By default, all
   8033 recommended warnings and some extra warnings are enabled (as by
   8034 `-Wall' and `-Wextra' respectively).
   8035 
   8036 Refer to the gcc manual at URL
   8037 `https://gcc.gnu.org/onlinedocs/gcc/' for more information about
   8038 warnings."
   8039   :type '(choice (const :tag "No additional warnings" nil)
   8040                  (repeat :tag "Additional warnings"
   8041                          (string :tag "Warning name")))
   8042   :safe #'flycheck-string-list-p
   8043   :package-version '(flycheck . "0.20"))
   8044 
   8045 (flycheck-define-checker c/c++-gcc
   8046   "A C/C++ syntax checker using GCC.
   8047 
   8048 Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
   8049   :command ("gcc"
   8050             "-fshow-column"
   8051             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   8052             (option "-std=" flycheck-gcc-language-standard concat)
   8053             (option-flag "-pedantic" flycheck-gcc-pedantic)
   8054             (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors)
   8055             (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions)
   8056             (option-flag "-fno-rtti" flycheck-gcc-no-rtti)
   8057             (option-flag "-fopenmp" flycheck-gcc-openmp)
   8058             (option-list "-include" flycheck-gcc-includes)
   8059             (option-list "-W" flycheck-gcc-warnings concat)
   8060             (option-list "-D" flycheck-gcc-definitions concat)
   8061             (option-list "-I" flycheck-gcc-include-path)
   8062             (eval flycheck-gcc-args)
   8063             "-x" (eval
   8064                   (pcase major-mode
   8065                     ((or `c++-mode `c++-ts-mode) "c++")
   8066                     ((or `c-mode `c-ts-mode) "c")))
   8067             ;; GCC performs full checking only when actually compiling, so
   8068             ;; `-fsyntax-only' is not enough. Just let it generate assembly
   8069             ;; code.
   8070             "-S" "-o" null-device
   8071             ;; Read from standard input
   8072             "-")
   8073   :standard-input t
   8074   :error-patterns
   8075   ((info line-start (or "<stdin>" (file-name))
   8076          ":" line (optional ":" column)
   8077          ": note: " (message) line-end)
   8078    (warning line-start (or "<stdin>" (file-name))
   8079             ":" line (optional ":" column)
   8080             ": warning: " (message (one-or-more (not (any "\n["))))
   8081             (optional "[" (id (one-or-more not-newline)) "]") line-end)
   8082    (error line-start (or "<stdin>" (file-name))
   8083           ":" line (optional ":" column)
   8084           ": " (or "fatal error" "error") ": " (message) line-end))
   8085   :modes (c-mode c++-mode c-ts-mode c++-ts-mode)
   8086   :next-checkers ((warning . c/c++-cppcheck)))
   8087 
   8088 (flycheck-def-option-var flycheck-cppcheck-checks '("style") c/c++-cppcheck
   8089   "Enabled checks for Cppcheck.
   8090 
   8091 The value of this variable is a list of strings, where each
   8092 string is the name of an additional check to enable.  By default,
   8093 all coding style checks are enabled.
   8094 
   8095 See section \"Enable message\" in the Cppcheck manual at URL
   8096 `https://cppcheck.sourceforge.net/manual.pdf', and the
   8097 documentation of the `--enable' option for more information,
   8098 including a list of supported checks."
   8099   :type '(repeat :tag "Additional checks"
   8100                  (string :tag "Check name"))
   8101   :safe #'flycheck-string-list-p
   8102   :package-version '(flycheck . "0.14"))
   8103 
   8104 (flycheck-def-option-var flycheck-cppcheck-standards nil c/c++-cppcheck
   8105   "The standards to use in cppcheck.
   8106 
   8107 The value of this variable is either a list of strings denoting
   8108 the standards to use, or nil to pass nothing to cppcheck.  When
   8109 non-nil, pass the standards via one or more `--std=' options."
   8110   :type '(choice (const :tag "Default" nil)
   8111                  (repeat :tag "Custom standards"
   8112                          (string :tag "Standard name")))
   8113   :safe #'flycheck-string-list-p
   8114   :package-version '(flycheck . "28"))
   8115 (make-variable-buffer-local 'flycheck-cppcheck-standards)
   8116 
   8117 (flycheck-def-option-var flycheck-cppcheck-suppressions-file nil c/c++-cppcheck
   8118   "The suppressions file to use in cppcheck.
   8119 
   8120 The value of this variable is a file with the suppressions to
   8121 use, or nil to pass nothing to cppcheck.  When non-nil, pass the
   8122 suppressions file via the `--suppressions-list=' option."
   8123   :type '(choice (const :tag "Default" nil)
   8124                  (file :tag "Suppressions file"))
   8125   :safe #'flycheck-string-or-nil-p
   8126   :package-version '(flycheck . "32"))
   8127 (make-variable-buffer-local 'flycheck-cppcheck-suppressions-file)
   8128 
   8129 (flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck
   8130   "The suppressions to use in cppcheck.
   8131 
   8132 The value of this variable is either a list of strings denoting
   8133 the suppressions to use, or nil to pass nothing to cppcheck.
   8134 When non-nil, pass the suppressions via one or more `--suppress='
   8135 options."
   8136   :type '(choice (const :tag "Default" nil)
   8137                  (repeat :tag "Additional suppressions"
   8138                          (string :tag "Suppression")))
   8139   :safe #'flycheck-string-list-p
   8140   :package-version '(flycheck . "28"))
   8141 
   8142 (flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck
   8143   "Whether to enable Cppcheck inconclusive checks.
   8144 
   8145 When non-nil, enable Cppcheck inconclusive checks.  This allows Cppcheck to
   8146 report warnings it's not certain of, but it may result in false positives.
   8147 
   8148 This will have no effect when using Cppcheck 1.53 and older."
   8149   :type 'boolean
   8150   :safe #'booleanp
   8151   :package-version '(flycheck . "0.19"))
   8152 
   8153 (flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck
   8154   "A list of include directories for cppcheck.
   8155 
   8156 The value of this variable is a list of strings, where each
   8157 string is a directory to add to the include path of cppcheck.
   8158 Relative paths are relative to the file being checked."
   8159   :type '(repeat (directory :tag "Include directory"))
   8160   :safe #'flycheck-string-list-p
   8161   :package-version '(flycheck . "0.24"))
   8162 
   8163 (flycheck-define-checker c/c++-cppcheck
   8164   "A C/C++ checker using cppcheck.
   8165 
   8166 See URL `https://cppcheck.sourceforge.net/'."
   8167   :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr"
   8168             (option "--enable=" flycheck-cppcheck-checks concat
   8169                     flycheck-option-comma-separated-list)
   8170             (option-flag "--inconclusive" flycheck-cppcheck-inconclusive)
   8171             (option-list "-I" flycheck-cppcheck-include-path)
   8172             (option-list "--std=" flycheck-cppcheck-standards concat)
   8173             (option-list "--suppress=" flycheck-cppcheck-suppressions concat)
   8174             (option "--suppressions-list="
   8175                     flycheck-cppcheck-suppressions-file concat)
   8176             "-x" (eval
   8177                   (pcase major-mode
   8178                     ((or `c++-mode `c++-ts-mode) "c++")
   8179                     ((or `c-mode `c-ts-mode) "c")))
   8180             source)
   8181   :error-parser flycheck-parse-cppcheck
   8182   :modes (c-mode c++-mode c-ts-mode c++-ts-mode))
   8183 
   8184 (flycheck-define-checker cfengine
   8185   "A CFEngine syntax checker using cf-promises.
   8186 
   8187 See URL `https://cfengine.com/'."
   8188   :command ("cf-promises" "-Wall" "-f"
   8189             ;; We must stay in the same directory to resolve @include
   8190             source-inplace)
   8191   :error-patterns
   8192   ((warning line-start (file-name) ":" line ":" column
   8193             ": warning: " (message) line-end)
   8194    (error line-start (file-name) ":" line ":" column
   8195           ": error: " (message) line-end))
   8196   :modes (cfengine-mode cfengine3-mode))
   8197 
   8198 (flycheck-define-checker coffee
   8199   "A CoffeeScript syntax checker using coffee.
   8200 
   8201 See URL `https://coffeescript.org/'."
   8202   ;; --print suppresses generation of compiled .js files
   8203   :command ("coffee" "--compile" "--print" "--stdio")
   8204   :standard-input t
   8205   :error-patterns
   8206   ((error line-start "[stdin]:" line ":" column
   8207           ": error: " (message) line-end))
   8208   :modes coffee-mode
   8209   :next-checkers ((warning . coffee-coffeelint)))
   8210 
   8211 (flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint
   8212                               ".coffeelint.json")
   8213 
   8214 (flycheck-define-checker coffee-coffeelint
   8215   "A CoffeeScript style checker using coffeelint.
   8216 
   8217 See URL `https://www.coffeelint.org/'."
   8218   :command
   8219   ("coffeelint"
   8220    (config-file "--file" flycheck-coffeelintrc)
   8221    "--stdin" "--reporter" "checkstyle")
   8222   :standard-input t
   8223   :error-parser flycheck-parse-checkstyle
   8224   :error-filter (lambda (errors)
   8225                   (flycheck-remove-error-file-names
   8226                    "stdin" (flycheck-remove-error-ids
   8227                             (flycheck-sanitize-errors errors))))
   8228   :modes coffee-mode)
   8229 
   8230 (flycheck-define-checker css-csslint
   8231   "A CSS syntax and style checker using csslint.
   8232 
   8233 See URL `https://github.com/CSSLint/csslint'."
   8234   :command ("csslint" "--format=checkstyle-xml" source)
   8235   :error-parser flycheck-parse-checkstyle
   8236   :error-filter flycheck-dequalify-error-ids
   8237   :modes (css-mode css-ts-mode))
   8238 
   8239 (defconst flycheck-stylelint-args '("--formatter" "json")
   8240   "Common arguments to stylelint invocations.")
   8241 
   8242 ;; Limit the length of the generated docstring by including only the first three
   8243 ;; checker symbols, otherwise emacs will complain about the docstring length
   8244 ;; and may refuse to compile the package.
   8245 (let ((print-length 3))
   8246   (flycheck-def-config-file-var flycheck-stylelintrc
   8247       (css-stylelint scss-stylelint sass-stylelint less-stylelint) nil))
   8248 
   8249 (flycheck-def-option-var flycheck-stylelint-quiet
   8250     nil (css-stylelint scss-stylelint sass-stylelint less-stylelint)
   8251   "Whether to run stylelint in quiet mode.
   8252 
   8253 When non-nil, enable quiet mode, via `--quiet'."
   8254   :type 'boolean
   8255   :safe #'booleanp
   8256   :package-version '(flycheck . 26))
   8257 
   8258 (defconst flycheck-stylelint-error-re
   8259   (flycheck-rx-to-string
   8260    '(: line-start (id (one-or-more word)) ": " (message) line-end)))
   8261 
   8262 (defun flycheck-parse-stylelint (output checker buffer)
   8263   "Parse stylelint errors from OUTPUT.
   8264 
   8265 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   8266 the BUFFER that was checked respectively.
   8267 
   8268 The CHECKER usually returns the errors as JSON.
   8269 
   8270 If the CHECKER throws an Error it returns an Error message with a stacktrace."
   8271   (condition-case nil
   8272       (flycheck-parse-stylelint-json output checker buffer)
   8273 
   8274     ;; The output could not be parsed as JSON
   8275     (json-error
   8276 
   8277      ;; Extract a flycheck error from the output (with a regular expression)
   8278      ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id
   8279      (when (string-match flycheck-stylelint-error-re output)
   8280        (list (flycheck-error-new-at
   8281               1 nil 'error
   8282               (match-string 4 output)
   8283               :id (match-string 5 output)
   8284               :checker checker
   8285               :buffer buffer
   8286               :filename (buffer-file-name buffer)))))))
   8287 
   8288 (defun flycheck-parse-stylelint-json (output checker buffer)
   8289   "Parse stylelint JSON errors from OUTPUT.
   8290 
   8291 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
   8292 the BUFFER that was checked respectively.
   8293 
   8294 See URL `https://stylelint.io/developer-guide/formatters/' for information
   8295 about the JSON format of stylelint."
   8296   (let ((json-object-type 'plist))
   8297 
   8298     ;; stylelint returns a vector of result objects
   8299     ;; Since we only passed one file, the first element is enough
   8300     (let* ((stylelint-output (elt (json-read-from-string output) 0))
   8301            (filename (buffer-file-name buffer))
   8302 
   8303            ;; Turn all deprecations into warnings
   8304            (deprecations
   8305             (mapcar (lambda (d)
   8306                       (flycheck-error-new-at
   8307                        1 nil 'warning
   8308                        (plist-get d :text)
   8309                        :id "Deprecation Warning"
   8310                        :checker checker
   8311                        :buffer buffer
   8312                        :filename filename))
   8313                     (plist-get stylelint-output :deprecations)))
   8314 
   8315            ;; Turn all invalid options into errors
   8316            (invalid-options
   8317             (mapcar (lambda (io)
   8318                       (flycheck-error-new-at
   8319                        1 nil 'error
   8320                        (plist-get io :text)
   8321                        :id "Invalid Option"
   8322                        :checker checker
   8323                        :buffer buffer
   8324                        :filename filename))
   8325                     (plist-get stylelint-output :invalidOptionWarnings)))
   8326 
   8327            ;; Read all linting warnings
   8328            (warnings
   8329             (mapcar (lambda (w)
   8330                       (flycheck-error-new-at
   8331                        (plist-get w :line) (plist-get w :column)
   8332                        (pcase (plist-get w :severity)
   8333                          (`"error"   'error)
   8334                          (`"warning" 'warning)
   8335                          ;; Default to info for unknown .severity
   8336                          (_          'info))
   8337                        (plist-get w :text)
   8338                        :id (plist-get w :rule)
   8339                        :checker checker
   8340                        :buffer buffer
   8341                        :filename filename))
   8342                     (plist-get stylelint-output :warnings))))
   8343 
   8344       ;; Return the combined errors (deprecations, invalid options, warnings)
   8345       (append deprecations invalid-options warnings))))
   8346 
   8347 (defun flycheck--stylelint-config-exists-p (checker)
   8348   "Whether there is a valid stylelint CHECKER config for the current buffer."
   8349   (eql 0 (flycheck-call-checker-process
   8350           checker nil nil nil
   8351           "--print-config" (or buffer-file-name "index.js"))))
   8352 
   8353 (defun flycheck--stylelint-get-major-version (checker)
   8354   "Return major version of stylelint CHECKER."
   8355   (let ((cb (current-buffer)))
   8356     (with-temp-buffer
   8357       (let ((temp-buffer (current-buffer)))
   8358         (with-current-buffer cb
   8359           (flycheck-call-checker-process
   8360            checker nil temp-buffer nil "--version"))
   8361         (string-to-number (car (split-string (buffer-string) "\\.")))))))
   8362 
   8363 (defun flycheck--stylelint-verify (checker)
   8364   "Verify stylelint setup for CHECKER."
   8365   (let ((have-config (flycheck--stylelint-config-exists-p checker)))
   8366     (list
   8367      (flycheck-verification-result-new
   8368       :label "configuration available"
   8369       :message (if have-config "yes" "no config file found")
   8370       :face (if have-config 'success '(bold error)))
   8371      (flycheck-verification-result-new
   8372       :label "stylecheck version"
   8373       :message (number-to-string (flycheck--stylelint-get-major-version checker))
   8374       :face 'success))))
   8375 
   8376 (flycheck-define-checker css-stylelint
   8377   "A CSS syntax and style checker using stylelint.
   8378 
   8379 See URL `https://stylelint.io/'."
   8380   :command ("stylelint"
   8381             (eval flycheck-stylelint-args)
   8382             (option-flag "--quiet" flycheck-stylelint-quiet)
   8383             (config-file "--config" flycheck-stylelintrc)
   8384             "--stdin-filename" (eval (or (buffer-file-name) "style.css")))
   8385   :standard-input t
   8386   :verify (lambda (_) (flycheck--stylelint-verify 'css-stylelint))
   8387   :error-parser flycheck-parse-stylelint
   8388   :predicate flycheck-buffer-nonempty-p
   8389   :modes (css-mode css-ts-mode)
   8390   :error-explainer
   8391   (lambda (err)
   8392     (let ((error-code (flycheck-error-id err))
   8393           (url "https://stylelint.io/user-guide/rules/%s"))
   8394       (and error-code `(url . ,(format url error-code))))))
   8395 
   8396 (flycheck-def-option-var flycheck-cuda-language-standard nil cuda-nvcc
   8397   "Our CUDA Language Standard."
   8398   :type '(choice (const :tag "Default standard" nil)
   8399                  (string :tag "Language standard"))
   8400   :safe #'flycheck-string-or-nil-p
   8401   :package-version '(flycheck . "32"))
   8402 (make-variable-buffer-local 'flycheck-cuda-language-standard)
   8403 
   8404 (flycheck-def-option-var flycheck-cuda-gencodes nil cuda-nvcc
   8405   "Our real and virtual GPU architectures to pass to nvcc."
   8406   :type '(repeat (file :tag "GPU architecture"))
   8407   :safe #'flycheck-string-list-p
   8408   :package-version '(flycheck . "32"))
   8409 
   8410 (flycheck-def-option-var flycheck-cuda-includes nil cuda-nvcc
   8411   "Our include directories to pass to nvcc."
   8412   :type '(repeat (file :tag "Include file"))
   8413   :safe #'flycheck-string-list-p
   8414   :package-version '(flycheck . "32"))
   8415 
   8416 (flycheck-def-option-var flycheck-cuda-definitions nil cuda-nvcc
   8417   "Additional preprocessor definitions for nvcc.
   8418 A list of strings to pass to cuda, a la flycheck-clang"
   8419   :type '(repeat (string :tag "Definitions"))
   8420   :safe #'flycheck-string-list-p
   8421   :package-version '(flycheck . "32"))
   8422 
   8423 (flycheck-def-option-var flycheck-cuda-include-path nil cuda-nvcc
   8424   "A list of include directories for nvcc."
   8425   :type '(repeat (directory :tag "Include directory"))
   8426   :safe #'flycheck-string-list-p
   8427   :package-version '(flycheck . "32"))
   8428 
   8429 (flycheck-def-option-var flycheck-cuda-relaxed-constexpr nil cuda-nvcc
   8430   "Enable calling host constexpr from device function for nvcc.
   8431 
   8432 When non-nil, enable experimental calling of a constexpr __host__
   8433 function from a __device__ function."
   8434   :type 'boolean
   8435   :safe #'booleanp
   8436   :package-version '(flycheck . "35"))
   8437 
   8438 (flycheck-def-option-var flycheck-cuda-extended-lambda nil cuda-nvcc
   8439   "Enable annotating lambda functions with __host__ or __device__.
   8440 
   8441 When non-nil, enable experimental compilation of __host__ and
   8442 __device__ lambda functions."
   8443   :type 'boolean
   8444   :safe #'booleanp
   8445   :package-version '(flycheck . "35"))
   8446 
   8447 (flycheck-define-checker cuda-nvcc
   8448   "A CUDA C/C++ syntax checker using nvcc.
   8449 
   8450 See URL `https://developer.nvidia.com/cuda-llvm-compiler'."
   8451   :command ("nvcc"
   8452             "-c" ;; Compile Only
   8453             "--output-file" "/dev/null" ;; avoid creating output .o
   8454             "--x=cu" ;; explicitly specify it's a CUDA language file
   8455             "-rdc=true" ;; Allow linking with external cuda funcions
   8456             (option "-std=" flycheck-cuda-language-standard concat)
   8457             (option-flag "--expt-relaxed-constexpr" flycheck-cuda-relaxed-constexpr)
   8458             (option-flag "--expt-extended-lambda" flycheck-cuda-extended-lambda)
   8459             (option-list "-include" flycheck-cuda-includes)
   8460             (option-list "-gencode" flycheck-cuda-gencodes)
   8461             (option-list "-D" flycheck-cuda-definitions concat)
   8462             (option-list "-I" flycheck-cuda-include-path)
   8463             source)
   8464   :error-patterns
   8465   ((error line-start
   8466           (message "In file included from")
   8467           " " (or "<stdin>" (file-name))
   8468           ":" line ":" line-end)
   8469    (error line-start (or "<stdin>" (file-name))
   8470           "(" line "): error: " (message) line-end)
   8471    (error line-start (or "<stdin>" (file-name))
   8472           ":" line ":" column
   8473           ": fatal error: " (optional (message)) line-end)
   8474    (warning line-start (or "<stdin>" (file-name))
   8475             "(" line "): warning: " (message) line-end))
   8476   :modes cuda-mode)
   8477 
   8478 
   8479 (flycheck-def-option-var flycheck-cwl-schema-path nil cwl
   8480   "A path for the schema file for Common Workflow Language.
   8481 
   8482 The value of this variable is a string that denotes a path for
   8483 the schema file of Common Workflow Language."
   8484   :type '(choice (const :tag "None" nil)
   8485                  (file :tag "Schema file"))
   8486   :safe #'flycheck-string-or-nil-p)
   8487 
   8488 (flycheck-define-checker cwl
   8489   "A CWL syntax checker using Schema Salad validator.
   8490 
   8491 Requires Schema Salad 2.6.20171101113912 or newer.
   8492 See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'."
   8493   :command ("schema-salad-tool"
   8494             "--quiet"
   8495             "--print-oneline"
   8496             (eval flycheck-cwl-schema-path)
   8497             source-inplace)
   8498   :error-patterns
   8499   ((error line-start
   8500           (file-name) ":" line ":" column ":" (zero-or-more blank)
   8501           (message (one-or-more not-newline))
   8502           line-end))
   8503   :modes cwl-mode)
   8504 
   8505 (defconst flycheck-d-module-re
   8506   (rx "module" (one-or-more (syntax whitespace))
   8507       (group (one-or-more (not (syntax whitespace))))
   8508       (zero-or-more (syntax whitespace))
   8509       ";")
   8510   "Regular expression to match a D module declaration.")
   8511 
   8512 (defun flycheck-d-base-directory ()
   8513   "Get the relative base directory path for this module."
   8514   (let* ((file-name (buffer-file-name))
   8515          (module-file (if (and file-name
   8516                                (string= (file-name-nondirectory file-name)
   8517                                         "package.d"))
   8518                           (directory-file-name (file-name-directory file-name))
   8519                         file-name)))
   8520     (flycheck-module-root-directory
   8521      (flycheck-find-in-buffer flycheck-d-module-re)
   8522      module-file)))
   8523 
   8524 (flycheck-def-option-var flycheck-dmd-include-path nil d-dmd
   8525   "A list of include directories for dmd.
   8526 
   8527 The value of this variable is a list of strings, where each
   8528 string is a directory to add to the include path of dmd.
   8529 Relative paths are relative to the file being checked."
   8530   :type '(repeat (directory :tag "Include directory"))
   8531   :safe #'flycheck-string-list-p
   8532   :package-version '(flycheck . "0.18"))
   8533 
   8534 (flycheck-def-args-var flycheck-dmd-args d-dmd
   8535   :package-version '(flycheck . "0.24"))
   8536 
   8537 (flycheck-define-checker d-dmd
   8538   "A D syntax checker using the DMD compiler.
   8539 
   8540 Requires DMD 2.066 or newer.  See URL `https://dlang.org/'."
   8541   :command ("dmd"
   8542             "-debug"                    ; Compile in debug mode
   8543             "-o-"                       ; Don't generate an object file
   8544             "-vcolumns"                 ; Add columns in output
   8545             "-wi" ; Compilation will continue even if there are warnings
   8546             (eval (concat "-I" (flycheck-d-base-directory)))
   8547             (option-list "-I" flycheck-dmd-include-path concat)
   8548             (eval flycheck-dmd-args)
   8549             (source ".d"))
   8550   :error-patterns
   8551   ((error line-start
   8552           (file-name) "(" line "," column "): Error: " (message)
   8553           line-end)
   8554    (warning line-start (file-name) "(" line "," column "): "
   8555             (or "Warning" "Deprecation") ": " (message) line-end)
   8556    (info line-start (file-name) "(" line "," column "): "
   8557          (one-or-more " ") (message) line-end))
   8558   :modes d-mode)
   8559 
   8560 (flycheck-define-checker dockerfile-hadolint
   8561   "A Dockerfile syntax checker using the hadolint.
   8562 
   8563 See URL `https://github.com/hadolint/hadolint/'."
   8564   :command ("hadolint" "--no-color" "-")
   8565   :standard-input t
   8566   :error-patterns
   8567   ((error line-start
   8568           (file-name) ":" line " " (id (one-or-more alnum)) " error: " (message)
   8569           line-end)
   8570    (warning line-start
   8571             (file-name) ":" line " " (id (one-or-more alnum))
   8572             " warning: " (message) line-end)
   8573    (info line-start
   8574          (file-name) ":" line " " (id (one-or-more alnum)) " info: " (message)
   8575          line-end)
   8576    (error line-start
   8577           (file-name) ":" line ":" column " " (message)
   8578           line-end))
   8579   :error-filter
   8580   (lambda (errors)
   8581     (flycheck-sanitize-errors
   8582      (flycheck-remove-error-file-names "-" errors)))
   8583   :modes (dockerfile-mode dockerfile-ts-mode))
   8584 
   8585 (defun flycheck-credo--working-directory (&rest _ignored)
   8586   "Check if `credo' is installed as dependency in the application."
   8587   (and buffer-file-name
   8588        (locate-dominating-file buffer-file-name "deps/credo")))
   8589 
   8590 (flycheck-def-option-var flycheck-elixir-credo-strict nil elixir-credo
   8591   "Enable strict mode in `credo'.
   8592 
   8593 When non-nil, pass the `--strict' flag to credo."
   8594   :type 'boolean
   8595   :safe #'booleanp
   8596   :package-version '(flycheck . "32"))
   8597 
   8598 (flycheck-define-checker elixir-credo
   8599   "An Elixir checker for static code analysis using Credo.
   8600 
   8601 See `https://credo-ci.org/'."
   8602   :command ("mix" "credo"
   8603             (option-flag "--strict" flycheck-elixir-credo-strict)
   8604             "--format" "flycheck"
   8605             "--read-from-stdin" source-original)
   8606   :standard-input t
   8607   :working-directory flycheck-credo--working-directory
   8608   :enabled flycheck-credo--working-directory
   8609   :error-patterns
   8610   ((info line-start
   8611          (file-name) ":" line (optional ":" column) ": "
   8612          (or "F" "R" "C")  ": " (message) line-end)
   8613    (warning line-start
   8614             (file-name) ":" line (optional ":" column) ": "
   8615             (or "D" "W")  ": " (message) line-end))
   8616   :modes elixir-mode)
   8617 
   8618 (defconst flycheck-this-emacs-executable
   8619   (concat invocation-directory invocation-name)
   8620   "The path to the currently running Emacs executable.")
   8621 
   8622 (defconst flycheck-emacs-args '("-Q" "--batch")
   8623   "Common arguments to Emacs invocations.")
   8624 
   8625 (defmacro flycheck-prepare-emacs-lisp-form (&rest body)
   8626   "Prepare BODY for use as check form in a subprocess."
   8627   (declare (indent 0))
   8628   `(flycheck-sexp-to-string
   8629     '(progn
   8630        (defvar jka-compr-inhibit)
   8631        (unwind-protect
   8632            ;; Flycheck inhibits compression of temporary files, thus we
   8633            ;; must not attempt to decompress.
   8634            (let ((jka-compr-inhibit t))
   8635              ;; Strip option-argument separator from arguments, if present
   8636              (when (equal (car command-line-args-left) "--")
   8637                (setq command-line-args-left (cdr command-line-args-left)))
   8638              ,@body)
   8639          ;; Prevent Emacs from processing the arguments on its own, see
   8640          ;; https://github.com/flycheck/flycheck/issues/319
   8641          (setq command-line-args-left nil)))))
   8642 
   8643 (defun flycheck-emacs-lisp-bytecomp-config-form ()
   8644   "Prepare an Emacs Lisp form to set byte-compiler variables."
   8645   (flycheck-sexp-to-string
   8646    `(progn
   8647       (require 'bytecomp)
   8648       (setq byte-compile-root-dir
   8649             ,(if buffer-file-name
   8650                  (file-name-directory buffer-file-name)
   8651                default-directory)))))
   8652 
   8653 (defconst flycheck-emacs-lisp-check-form
   8654   (flycheck-prepare-emacs-lisp-form
   8655     ;; Keep track of the generated bytecode files, to delete them after byte
   8656     ;; compilation.
   8657     (require 'bytecomp)
   8658     (defvar flycheck-byte-compiled-files nil)
   8659     (let ((byte-compile-dest-file-function
   8660            (lambda (source)
   8661              (let ((temp-file (make-temp-file (file-name-nondirectory source))))
   8662                (push temp-file flycheck-byte-compiled-files)
   8663                temp-file))))
   8664       (unwind-protect
   8665           (byte-compile-file (car command-line-args-left))
   8666         (mapc (lambda (f) (ignore-errors (delete-file f)))
   8667               flycheck-byte-compiled-files))
   8668       (when (bound-and-true-p flycheck-emacs-lisp-check-declare)
   8669         (check-declare-file (car command-line-args-left))))))
   8670 
   8671 (flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp
   8672   "Load path to use in the Emacs Lisp syntax checker.
   8673 
   8674 When set to `inherit', use the `load-path' of the current Emacs
   8675 session during syntax checking.
   8676 
   8677 When set to a list of strings, add each directory in this list to
   8678 the `load-path' before invoking the byte compiler.  Relative
   8679 paths in this list are expanded against the `default-directory'
   8680 of the buffer to check.
   8681 
   8682 When nil, do not explicitly set the `load-path' during syntax
   8683 checking.  The syntax check only uses the built-in `load-path' of
   8684 Emacs in this case.
   8685 
   8686 Note that changing this variable can lead to wrong results of the
   8687 syntax check, e.g. if an unexpected version of a required library
   8688 is used."
   8689   :type '(choice (const :tag "Inherit current `load-path'" inherit)
   8690                  (repeat :tag "Load path" directory))
   8691   :risky t
   8692   :package-version '(flycheck . "0.14"))
   8693 
   8694 (flycheck-def-option-var flycheck-emacs-lisp-initialize-packages
   8695     'auto emacs-lisp
   8696   "Whether to initialize packages in the Emacs Lisp syntax checker.
   8697 
   8698 When nil, never initialize packages.  When `auto', initialize
   8699 packages only when checking `user-init-file' or files from
   8700 `user-emacs-directory'.  For any other non-nil value, always
   8701 initialize packages.
   8702 
   8703 When initializing packages is enabled the `emacs-lisp' syntax
   8704 checker calls `package-initialize' before byte-compiling the file
   8705 to be checked.  It also sets `package-user-dir' according to
   8706 `flycheck-emacs-lisp-package-user-dir'."
   8707   :type '(choice (const :tag "Do not initialize packages" nil)
   8708                  (const :tag "Initialize packages for configuration only" auto)
   8709                  (const :tag "Always initialize packages" t))
   8710   :risky t
   8711   :package-version '(flycheck . "0.14"))
   8712 
   8713 (defconst flycheck-emacs-lisp-package-initialize-form
   8714   (flycheck-sexp-to-string
   8715    '(with-demoted-errors "Error during package initialization: %S"
   8716       (package-initialize)))
   8717   "Form used to initialize packages.")
   8718 
   8719 (defun flycheck-option-emacs-lisp-package-initialize (value)
   8720   "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'."
   8721   (let ((shall-initialize
   8722          (if (eq value 'auto)
   8723              (or (flycheck-in-user-emacs-directory-p
   8724                   (or buffer-file-name default-directory))
   8725                  ;; `user-init-file' is nil in non-interactive sessions.  Now,
   8726                  ;; no user would possibly use Flycheck in a non-interactive
   8727                  ;; session, but our unit tests run non-interactively, so we
   8728                  ;; have to handle this case anyway
   8729                  (and user-init-file buffer-file-name
   8730                       (flycheck-same-files-p buffer-file-name user-init-file)))
   8731            value)))
   8732     (when shall-initialize
   8733       ;; If packages shall be initialized, return the corresponding form,
   8734       ;; otherwise make Flycheck ignore the option by returning nil.
   8735       flycheck-emacs-lisp-package-initialize-form)))
   8736 
   8737 (flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp
   8738   "Package directory for the Emacs Lisp syntax checker.
   8739 
   8740 If set to a string set `package-user-dir' to the value of this
   8741 variable before initializing packages. If set to nil just inherit
   8742 the value of `package-user-dir' from the running Emacs session.
   8743 
   8744 This variable has no effect, if
   8745 `flycheck-emacs-lisp-initialize-packages' is nil."
   8746   :type '(choice (const :tag "Default package directory" nil)
   8747                  (directory :tag "Custom package directory"))
   8748   :risky t
   8749   :package-version '(flycheck . "0.14"))
   8750 
   8751 (defun flycheck-option-emacs-lisp-package-user-dir (value)
   8752   "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'."
   8753   ;; Inherit the package directory from our Emacs session
   8754   (let ((value (or value (bound-and-true-p package-user-dir))))
   8755     (when value
   8756       (flycheck-sexp-to-string `(setq package-user-dir ,value)))))
   8757 
   8758 (flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp
   8759   "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’."
   8760   :type '(choice (const :tag "Do not check declare forms" nil)
   8761                  (const :tag "Check declare forms" t))
   8762   :risky t
   8763   :package-version '(flycheck . "31"))
   8764 
   8765 (defun flycheck-option-emacs-lisp-check-declare (value)
   8766   "Option VALUE filter for `flycheck-emacs-lisp-check-declare'."
   8767   (when value
   8768     (flycheck-sexp-to-string
   8769      `(progn
   8770         (defvar flycheck-emacs-lisp-check-declare)
   8771         (setq flycheck-emacs-lisp-check-declare ,value)))))
   8772 
   8773 (defun flycheck--emacs-lisp-enabled-p ()
   8774   "Check whether to enable Emacs Lisp checker in the current buffer."
   8775   (not
   8776    (or
   8777     ;; Do not check buffers used for autoloads generation during package
   8778     ;; installation.  These buffers are too short-lived for being checked, and
   8779     ;; doing so causes spurious errors.  See
   8780     ;; https://github.com/flycheck/flycheck/issues/45 and
   8781     ;; https://github.com/bbatsov/prelude/issues/248.  We must also not check
   8782     ;; compilation buffers, but as these are ephemeral, Flycheck won't check
   8783     ;; them anyway.
   8784     (flycheck-autoloads-file-p)
   8785     ;; Cask/Carton and dir-locals files contain data, not code, and don't need
   8786     ;; to follow Checkdoc conventions either.
   8787     (and (buffer-file-name)
   8788          (member (file-name-nondirectory (buffer-file-name))
   8789                  '("Cask" "Carton" ".dir-locals.el" ".dir-locals-2.el"))))))
   8790 
   8791 (defun flycheck--emacs-lisp-checkdoc-enabled-p ()
   8792   "Check whether to enable Emacs Lisp Checkdoc in the current buffer."
   8793   (and (flycheck--emacs-lisp-enabled-p)
   8794        ;; These files are valid Lisp, but don't contain "standard" comments.
   8795        (not (member (buffer-file-name) '("Eldev" "Eldev-local")))))
   8796 
   8797 (flycheck-define-checker emacs-lisp
   8798   "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler.
   8799 
   8800 See Info Node `(elisp)Byte Compilation'."
   8801   :command ("emacs" (eval flycheck-emacs-args)
   8802             (eval
   8803              (let ((path (pcase flycheck-emacs-lisp-load-path
   8804                            (`inherit load-path)
   8805                            (p (seq-map #'expand-file-name p)))))
   8806                (flycheck-prepend-with-option "--directory" path)))
   8807             (option "--eval" flycheck-emacs-lisp-package-user-dir nil
   8808                     flycheck-option-emacs-lisp-package-user-dir)
   8809             (option "--eval" flycheck-emacs-lisp-initialize-packages nil
   8810                     flycheck-option-emacs-lisp-package-initialize)
   8811             (option "--eval" flycheck-emacs-lisp-check-declare nil
   8812                     flycheck-option-emacs-lisp-check-declare)
   8813             "--eval" (eval (flycheck-emacs-lisp-bytecomp-config-form))
   8814             "--eval" (eval flycheck-emacs-lisp-check-form)
   8815             "--"
   8816             source-inplace)
   8817   :error-patterns
   8818   ((error line-start (file-name) ":" line ":" column ":"
   8819           (zero-or-more whitespace) "Error:" (zero-or-more whitespace)
   8820           (message (zero-or-more not-newline)
   8821                    (zero-or-more "\n    " (zero-or-more not-newline)))
   8822           line-end)
   8823    (warning line-start (file-name) ":" line ":" column ":"
   8824             (zero-or-more whitespace) "Warning:" (zero-or-more whitespace)
   8825             (message (zero-or-more not-newline)
   8826                      (zero-or-more "\n    " (zero-or-more not-newline)))
   8827             line-end)
   8828    (warning line-start (file-name) ":" line (optional ":" column) ":"
   8829             (zero-or-more whitespace) "Warning (check-declare): said\n"
   8830             (message (zero-or-more "    " (zero-or-more not-newline))
   8831                      (zero-or-more "\n    " (zero-or-more not-newline)))
   8832             line-end)
   8833    ;; The following is for Emacs 24 ‘check-declare-file’, which uses a
   8834    ;; less informative format.
   8835    (warning line-start "Warning (check-declare): " (file-name) " said "
   8836             (message (zero-or-more not-newline))
   8837             line-end))
   8838   :error-filter
   8839   (lambda (errors)
   8840     (flycheck-fill-empty-line-numbers
   8841      (flycheck-collapse-error-message-whitespace
   8842       (flycheck-sanitize-errors errors))))
   8843   :modes (emacs-lisp-mode lisp-interaction-mode)
   8844   :enabled flycheck--emacs-lisp-enabled-p
   8845   :predicate
   8846   (lambda ()
   8847     ;; Do not check buffers that should not be byte-compiled.  The checker
   8848     ;; process will refuse to compile these, which would confuse Flycheck
   8849     (not (bound-and-true-p no-byte-compile)))
   8850   :next-checkers (emacs-lisp-checkdoc))
   8851 
   8852 (defconst flycheck-emacs-lisp-checkdoc-form
   8853   (flycheck-prepare-emacs-lisp-form
   8854     (unless (require 'elisp-mode nil 'no-error)
   8855       ;; TODO: Fallback for Emacs 24, remove when dropping support for 24
   8856       (require 'lisp-mode))
   8857     (require 'checkdoc)
   8858 
   8859     (let ((source (car command-line-args-left))
   8860           ;; Remember the default directory of the process
   8861           (process-default-directory default-directory))
   8862       ;; Note that we deliberately use our custom approach even despite of
   8863       ;; `checkdoc-file' which was added to Emacs 25.1.  While it's conceptually
   8864       ;; the better thing, its implementation has too many flaws to be of use
   8865       ;; for us.
   8866       (with-temp-buffer
   8867         (insert-file-contents source 'visit)
   8868         (setq buffer-file-name source)
   8869         ;; And change back to the process default directory to make file-name
   8870         ;; back-substutition work
   8871         (setq default-directory process-default-directory)
   8872         (with-demoted-errors "Error in checkdoc: %S"
   8873           ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to
   8874           ;; parse sexps and identify docstrings correctly; see
   8875           ;; https://github.com/flycheck/flycheck/issues/833
   8876           (delay-mode-hooks (emacs-lisp-mode))
   8877           (setq delayed-mode-hooks nil)
   8878           (checkdoc-current-buffer t)
   8879           (with-current-buffer checkdoc-diagnostic-buffer
   8880             (princ (buffer-substring-no-properties (point-min) (point-max)))
   8881             (kill-buffer)))))))
   8882 
   8883 (defconst flycheck-emacs-lisp-checkdoc-variables
   8884   `(checkdoc-symbol-words
   8885     checkdoc-arguments-in-order-flag
   8886     checkdoc-force-history-flag
   8887     checkdoc-permit-comma-termination-flag
   8888     checkdoc-force-docstrings-flag
   8889     checkdoc-package-keywords-flag
   8890     checkdoc-spellcheck-documentation-flag
   8891     checkdoc-verb-check-experimental-flag
   8892     checkdoc-max-keyref-before-warn
   8893     sentence-end-double-space
   8894     ,@(and (>= emacs-major-version 28)
   8895            '(checkdoc-column-zero-backslash-before-paren)))
   8896   "Variables inherited by the checkdoc subprocess.")
   8897 
   8898 (defun flycheck-emacs-lisp-checkdoc-variables-form ()
   8899   "Make a sexp to pass relevant variables to a checkdoc subprocess.
   8900 
   8901 Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'."
   8902   `(progn
   8903      ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
   8904                 (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables))))
   8905 
   8906 (flycheck-define-checker emacs-lisp-checkdoc
   8907   "An Emacs Lisp style checker using CheckDoc.
   8908 
   8909 The checker runs `checkdoc-current-buffer'."
   8910   :command ("emacs" (eval flycheck-emacs-args)
   8911             "--eval" (eval (flycheck-sexp-to-string
   8912                             (flycheck-emacs-lisp-checkdoc-variables-form)))
   8913             "--eval" (eval flycheck-emacs-lisp-checkdoc-form)
   8914             "--" source)
   8915   :error-patterns
   8916   ((info line-start (file-name) ":" line ": " (message) line-end))
   8917   :modes (emacs-lisp-mode)
   8918   :enabled flycheck--emacs-lisp-checkdoc-enabled-p)
   8919 
   8920 (dolist (checker '(emacs-lisp emacs-lisp-checkdoc))
   8921   (setf (car (flycheck-checker-get checker 'command))
   8922         flycheck-this-emacs-executable))
   8923 
   8924 (defun flycheck-ember-template--check-for-config (&rest _ignored)
   8925   "Check the required config file is available up the file system."
   8926   (and buffer-file-name
   8927        (locate-dominating-file buffer-file-name ".template-lintrc.js")))
   8928 
   8929 (defun flycheck-ember-template--parse-error (output checker buffer)
   8930   "Parse Ember-template-lint errors/warnings from JSON OUTPUT.
   8931 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   8932 the BUFFER that was checked respectively."
   8933   (mapcar (lambda (err)
   8934             (let-alist err
   8935               (flycheck-error-new-at
   8936                .line
   8937                .column
   8938                (pcase .severity
   8939                  (2 'error)
   8940                  (1 'warning)
   8941                  (_ 'warning))
   8942                .message
   8943                :id .rule
   8944                :checker checker
   8945                :buffer buffer
   8946                :filename (buffer-file-name buffer))))
   8947           (cdr (car (car (flycheck-parse-json output))))))
   8948 
   8949 (flycheck-def-config-file-var flycheck-ember-template-lintrc
   8950     ember-template
   8951     ".template-lintrc.js")
   8952 
   8953 (flycheck-define-checker ember-template
   8954   "An Ember template checker using ember-template-lint."
   8955   :command ("ember-template-lint"
   8956             (config-file "--config-path" flycheck-ember-template-lintrc)
   8957             "--filename" source-original
   8958             "--format=json")
   8959   :standard-input t
   8960   :error-parser flycheck-ember-template--parse-error
   8961   :modes web-mode
   8962   :enabled flycheck-ember-template--check-for-config
   8963   :working-directory flycheck-ember-template--check-for-config)
   8964 
   8965 (flycheck-def-option-var flycheck-erlang-include-path nil erlang
   8966   "A list of include directories for Erlang.
   8967 
   8968 The value of this variable is a list of strings, where each
   8969 string is a directory to add to the include path of erlc.
   8970 Relative paths are relative to the file being checked."
   8971   :type '(repeat (directory :tag "Include directory"))
   8972   :safe #'flycheck-string-list-p
   8973   :package-version '(flycheck . "0.24"))
   8974 
   8975 (flycheck-def-option-var flycheck-erlang-library-path nil erlang
   8976   "A list of library directories for Erlang.
   8977 
   8978 The value of this variable is a list of strings, where each
   8979 string is a directory to add to the library path of erlc.
   8980 Relative paths are relative to the file being checked."
   8981   :type '(repeat (directory :tag "Library directory"))
   8982   :safe #'flycheck-string-list-p
   8983   :package-version '(flycheck . "0.24"))
   8984 
   8985 (flycheck-define-checker erlang
   8986   "An Erlang syntax checker using the Erlang interpreter.
   8987 
   8988 See URL `https://www.erlang.org/'."
   8989   :command ("erlc"
   8990             "-o" temporary-directory
   8991             (option-list "-I" flycheck-erlang-include-path)
   8992             (option-list "-pa" flycheck-erlang-library-path)
   8993             "-Wall"
   8994             source)
   8995   :error-patterns
   8996   ((warning line-start (file-name) ":" line ":" (optional column ":")
   8997             " Warning:" (message) line-end)
   8998    (error line-start (file-name) ":" line ":" (optional column ":") " "
   8999           (message) line-end))
   9000   :modes erlang-mode
   9001   :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name))))
   9002 
   9003 (defun flycheck--contains-rebar-config (dir-name)
   9004   "Return DIR-NAME if rebar config file exists in DIR-NAME, nil otherwise."
   9005   (when (or (file-exists-p (expand-file-name "rebar.config" dir-name))
   9006             (file-exists-p (expand-file-name "rebar.config.script" dir-name)))
   9007     dir-name))
   9008 
   9009 (defun flycheck--locate-rebar3-project-root
   9010     (file-name &optional prev-file-name acc)
   9011   "Find the top-most rebar project root for source FILE-NAME.
   9012 
   9013 A project root directory is any directory containing a
   9014 rebar.config file.  Find the top-most directory to move out of any
   9015 nested dependencies.
   9016 
   9017 FILE-NAME is a source file for which to find the project.
   9018 
   9019 PREV-FILE-NAME helps us prevent infinite looping
   9020 
   9021 ACC is an accumulator that keeps the list of results, the first
   9022 non-nil of which will be our project root.
   9023 
   9024 Return the absolute path to the directory"
   9025   (if (string= file-name prev-file-name)
   9026       (car (remove nil acc))
   9027     (let ((current-dir (file-name-directory file-name)))
   9028       (flycheck--locate-rebar3-project-root
   9029        (directory-file-name current-dir)
   9030        file-name
   9031        (cons (flycheck--contains-rebar-config current-dir) acc)))))
   9032 
   9033 (defun flycheck-rebar3-project-root (&optional _checker)
   9034   "Return directory where rebar.config is located."
   9035   (flycheck--locate-rebar3-project-root buffer-file-name))
   9036 
   9037 (flycheck-def-option-var flycheck-erlang-rebar3-profile nil erlang-rebar3
   9038   "The rebar3 profile to use.
   9039 
   9040 The profile used when compiling, if VALUE is nil \"test\" will be used
   9041 when the file is located in test directory, otherwise \"default\" will be
   9042 used as profile."
   9043   :type '(choice (const :tag "Automatic" nil)
   9044                  (string :tag "Profile"))
   9045   :safe #'flycheck-string-or-nil-p
   9046   :package-version '(flycheck . "32"))
   9047 
   9048 (defun flycheck-erlang-rebar3-get-profile ()
   9049   "Return rebar3 profile.
   9050 
   9051 Use flycheck-erlang-rebar3-profile if set, otherwise use test or eqc profile if
   9052 directory name is \"test\" or \"eqc\", or else \"default\"."
   9053   (or
   9054    flycheck-erlang-rebar3-profile
   9055    (with-no-warnings
   9056      ;; `seq-contains-p' is only in seq >= 2.21
   9057      (seq-contains '("test" "eqc")
   9058                    (and buffer-file-name
   9059                         (file-name-base
   9060                          (directory-file-name
   9061                           (file-name-directory buffer-file-name))))))
   9062    "default"))
   9063 
   9064 (flycheck-define-checker erlang-rebar3
   9065   "An Erlang syntax checker using the rebar3 build tool."
   9066   :command ("rebar3" "as" (eval (flycheck-erlang-rebar3-get-profile)) "compile")
   9067   :error-parser flycheck-parse-with-patterns-without-color
   9068   :error-patterns
   9069   ((warning line-start (file-name) ":" line ":" (optional column ":")
   9070             " Warning:" (message) line-end)
   9071    (error line-start (file-name) ":" line ":" (optional column ":") " "
   9072           (message) line-end))
   9073   :modes erlang-mode
   9074   :enabled flycheck-rebar3-project-root
   9075   :predicate flycheck-buffer-saved-p
   9076   :working-directory flycheck-rebar3-project-root)
   9077 
   9078 (flycheck-define-checker eruby-erubis
   9079   "An eRuby syntax checker using the `erubis' command.
   9080 
   9081 See URL `https://www.kuwata-lab.com/erubis/'."
   9082   :command ("erubis" "-z" source)
   9083   :error-patterns
   9084   ((error line-start (file-name) ":" line ": " (message) line-end))
   9085   :modes (html-erb-mode rhtml-mode)
   9086   :next-checkers ((warning . eruby-ruumba)))
   9087 
   9088 (flycheck-def-config-file-var flycheck-ruumbarc eruby-ruumba ".ruumba.yml")
   9089 
   9090 (flycheck-def-option-var flycheck-ruumba-lint-only nil eruby-ruumba
   9091   "Whether to only report code issues in Ruumba.
   9092 
   9093 When non-nil, only report code issues in Ruumba, via `--lint'.
   9094 Otherwise report style issues as well."
   9095   :safe #'booleanp
   9096   :type 'boolean
   9097   :package-version '(flycheck . "32"))
   9098 
   9099 (flycheck-define-checker eruby-ruumba
   9100   "An eRuby syntax and style checker using the Ruumba tool.
   9101 
   9102 You need at least Ruumba 0.1.7 for this syntax checker.
   9103 
   9104 See URL `https://github.com/ericqweinstein/ruumba'."
   9105   :command ("ruumba"
   9106             "--display-cop-names"
   9107             "--force-exclusion"
   9108             "--format" "emacs"
   9109             "--cache" "false"
   9110             (config-file "--config" flycheck-ruumbarc)
   9111             (option-flag "--lint" flycheck-ruumba-lint-only)
   9112             ;; Ruumba takes the original file name as argument when reading
   9113             ;; from standard input
   9114             "--stdin" source-original)
   9115   :standard-input t
   9116   :working-directory flycheck-ruby--find-project-root
   9117   :error-patterns
   9118   ((info line-start (file-name) ":" line ":" column ": C: "
   9119          (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
   9120    (warning line-start (file-name) ":" line ":" column ": W: "
   9121             (optional (id (one-or-more (not (any ":")))) ": ") (message)
   9122             line-end)
   9123    (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
   9124           (optional (id (one-or-more (not (any ":")))) ": ") (message)
   9125           line-end))
   9126   :modes (html-erb-mode rhtml-mode))
   9127 
   9128 (flycheck-def-args-var flycheck-gfortran-args fortran-gfortran
   9129   :package-version '(flycheck . "0.22"))
   9130 
   9131 (flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran
   9132   "A list of include directories for GCC Fortran.
   9133 
   9134 The value of this variable is a list of strings, where each
   9135 string is a directory to add to the include path of gcc.
   9136 Relative paths are relative to the file being checked."
   9137   :type '(repeat (directory :tag "Include directory"))
   9138   :safe #'flycheck-string-list-p
   9139   :package-version '(flycheck . "0.20"))
   9140 
   9141 (flycheck-def-option-var flycheck-gfortran-language-standard "f95"
   9142                          fortran-gfortran
   9143   "The language standard to use in GFortran.
   9144 
   9145 The value of this variable is either a string denoting a language
   9146 standard, or nil, to use the default standard.  When non-nil,
   9147 pass the language standard via the `-std' option."
   9148   :type '(choice (const :tag "Default standard" nil)
   9149                  (string :tag "Language standard"))
   9150   :package-version '(flycheck . "0.20"))
   9151 
   9152 (flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran
   9153   "The source code layout to use in GFortran.
   9154 
   9155 The value of this variable is one of the following symbols:
   9156 
   9157 nil
   9158      Let gfortran determine the layout from the extension
   9159 
   9160 `free'
   9161      Use free form layout
   9162 
   9163 
   9164 `fixed'
   9165      Use fixed form layout
   9166 
   9167 In any other case, an error is signaled."
   9168   :type '(choice (const :tag "Guess layout from extension" nil)
   9169                  (const :tag "Free form layout" free)
   9170                  (const :tag "Fixed form layout" fixed))
   9171   :safe (lambda (value) (or (not value) (memq value '(free fixed))))
   9172   :package-version '(flycheck . "0.20"))
   9173 
   9174 (defun flycheck-option-gfortran-layout (value)
   9175   "Option VALUE filter for `flycheck-gfortran-layout'."
   9176   (pcase value
   9177     (`nil nil)
   9178     (`free "free-form")
   9179     (`fixed "fixed-form")
   9180     (_ (error "Invalid value for flycheck-gfortran-layout: %S" value))))
   9181 
   9182 (flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra")
   9183                          fortran-gfortran
   9184   "A list of warnings for GCC Fortran.
   9185 
   9186 The value of this variable is a list of strings, where each string
   9187 is the name of a warning category to enable.  By default, all
   9188 recommended warnings and some extra warnings are enabled (as by
   9189 `-Wall' and `-Wextra' respectively).
   9190 
   9191 Refer to the gfortran manual at URL
   9192 `https://gcc.gnu.org/onlinedocs/gfortran/' for more information
   9193 about warnings"
   9194   :type '(choice (const :tag "No additional warnings" nil)
   9195                  (repeat :tag "Additional warnings"
   9196                          (string :tag "Warning name")))
   9197   :safe #'flycheck-string-list-p
   9198   :package-version '(flycheck . "0.20"))
   9199 
   9200 (flycheck-define-checker fortran-gfortran
   9201   "An Fortran syntax checker using GCC.
   9202 
   9203 Uses GCC's Fortran compiler gfortran.  See URL
   9204 `https://gcc.gnu.org/onlinedocs/gfortran/'."
   9205   :command ("gfortran"
   9206             "-fsyntax-only"
   9207             "-fshow-column"
   9208             ;; Do not visually indicate the source location
   9209             "-fno-diagnostics-show-caret"
   9210             ;; Do not show the corresponding warning group
   9211             "-fno-diagnostics-show-option"
   9212             ;; Fortran has similar include processing as C/C++
   9213             "-iquote" (eval (flycheck-c/c++-quoted-include-directory))
   9214             (option "-std=" flycheck-gfortran-language-standard concat)
   9215             (option "-f" flycheck-gfortran-layout concat
   9216                     flycheck-option-gfortran-layout)
   9217             (option-list "-W" flycheck-gfortran-warnings concat)
   9218             (option-list "-I" flycheck-gfortran-include-path concat)
   9219             (eval flycheck-gfortran-args)
   9220             source)
   9221   :error-patterns
   9222   ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
   9223           (or (= 3 (zero-or-more not-newline) "\n") "")
   9224           (or "Error" "Fatal Error") ": "
   9225           (message) line-end)
   9226    (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n")
   9227             (or (= 3 (zero-or-more not-newline) "\n") "")
   9228             "Warning: " (message) line-end))
   9229   :modes (fortran-mode f90-mode))
   9230 
   9231 (flycheck-define-checker yaml-actionlint
   9232   "A YAML syntax checker using actionlint.
   9233 
   9234 See URL https://github.com/rhysd/actionlint/."
   9235   :command ("actionlint" "-oneline" source)
   9236   :error-patterns ((error line-start (file-name) ":" line ":" column ": " (message) line-end))
   9237   :modes (yaml-mode yaml-ts-mode)
   9238   :predicate (lambda ()
   9239                (string-match-p
   9240                 (rx (or ".github/workflows" ".github\\workflows"))
   9241                 (buffer-file-name))))
   9242 
   9243 (flycheck-define-checker go-gofmt
   9244   "A Go syntax and style checker using the gofmt utility.
   9245 
   9246 See URL `https://golang.org/cmd/gofmt/'."
   9247   :command ("gofmt")
   9248   :standard-input t
   9249   :error-patterns
   9250   ((error line-start "<standard input>:" line ":" column ": "
   9251           (message) line-end))
   9252   :modes (go-mode go-ts-mode)
   9253   :next-checkers ((warning . go-vet)
   9254                   ;; Fall back, if go-vet doesn't exist
   9255                   (warning . go-build) (warning . go-test)
   9256                   (warning . go-errcheck)
   9257                   (warning . go-unconvert)
   9258                   (warning . go-staticcheck)))
   9259 
   9260 (flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet
   9261   "A list of print-like functions for `go vet'.
   9262 
   9263 Go vet will check these functions for format string problems and
   9264 issues, such as a mismatch between the number of formats used,
   9265 and the number of arguments given.
   9266 
   9267 Each entry is in the form Name:N where N is the zero-based
   9268 argument position of the first argument involved in the print:
   9269 either the format or the first print argument for non-formatted
   9270 prints.  For example, if you have Warn and Warnf functions that
   9271 take an io.Writer as their first argument, like Fprintf,
   9272 -printfuncs=Warn:1,Warnf:1 "
   9273   :type '(repeat :tag "print-like functions"
   9274                  (string :tag "function"))
   9275   :safe #'flycheck-string-list-p)
   9276 
   9277 (flycheck-define-checker go-vet
   9278   "A Go syntax checker using the `go vet' command.
   9279 
   9280 See URL `https://golang.org/cmd/go/' and URL
   9281 `https://golang.org/cmd/vet/'."
   9282   :command ("go" "vet"
   9283             (option "-printf.funcs=" flycheck-go-vet-print-functions concat
   9284                     flycheck-option-comma-separated-list)
   9285             (source ".go"))
   9286   :error-patterns
   9287   ((warning line-start (file-name) ":" line ": " (message) line-end))
   9288   :modes (go-mode go-ts-mode)
   9289   :next-checkers (go-build
   9290                   go-test
   9291                   ;; Fall back if `go build' or `go test' can be used
   9292                   go-errcheck
   9293                   go-unconvert
   9294                   go-staticcheck)
   9295   :verify (lambda (_)
   9296             (let* ((go (flycheck-checker-executable 'go-vet))
   9297                    (have-vet (member "vet" (ignore-errors
   9298                                              (process-lines go "tool")))))
   9299               (list
   9300                (flycheck-verification-result-new
   9301                 :label "go tool vet"
   9302                 :message (if have-vet "present" "missing")
   9303                 :face (if have-vet 'success '(bold error)))))))
   9304 
   9305 (flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test)
   9306   "Whether to install dependencies in `go build' and `go test'.
   9307 
   9308 If non-nil automatically install dependencies with `go build'
   9309 while syntax checking."
   9310   :type 'boolean
   9311   :safe #'booleanp
   9312   :package-version '(flycheck . "0.25"))
   9313 
   9314 (flycheck-def-option-var flycheck-go-build-tags nil
   9315                          (go-build go-test go-errcheck go-staticcheck)
   9316   "A list of tags for `go build'.
   9317 
   9318 Each item is a string with a tag to be given to `go build'."
   9319   :type '(repeat (string :tag "Tag"))
   9320   :safe #'flycheck-string-list-p
   9321   :package-version '(flycheck . "0.25"))
   9322 
   9323 
   9324 (flycheck-def-option-var flycheck-go-version nil go-staticcheck
   9325   "The version of go that should be targeted by `staticcheck'.
   9326 
   9327 Should be a string representing a version, like 1.6 or 1.11.4.
   9328 See `https://staticcheck.io/docs/#targeting-go-versions' for
   9329 details."
   9330   :type '(choice (const :tag "Unspecified" nil)
   9331                  (string :tag "Version"))
   9332   :safe #'flycheck-string-or-nil-p
   9333   :package-version '(flycheck . "0.32"))
   9334 
   9335 (flycheck-define-checker go-build
   9336   "A Go syntax and type checker using the `go build' command.
   9337 
   9338 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
   9339   :command ("go" "build"
   9340             (option-flag "-i" flycheck-go-build-install-deps)
   9341             ;; multiple tags are listed as "dev debug ..."
   9342             (option-list "-tags=" flycheck-go-build-tags concat)
   9343             "-o" null-device)
   9344   :error-patterns
   9345   ((error line-start (file-name) ":" line ":"
   9346           (optional column ":") " "
   9347           (message (one-or-more not-newline)
   9348                    (zero-or-more "\n\t" (one-or-more not-newline)))
   9349           line-end)
   9350    ;; Catch error message about multiple packages in a directory, which doesn't
   9351    ;; follow the standard error message format.
   9352    (info line-start
   9353          (message "can't load package: package "
   9354                   (one-or-more (not (any ?: ?\n)))
   9355                   ": found packages "
   9356                   (one-or-more not-newline))
   9357          line-end))
   9358   :error-filter
   9359   (lambda (errors)
   9360     (dolist (error errors)
   9361       (unless (flycheck-error-line error)
   9362         ;; Flycheck ignores errors without line numbers, but the error
   9363         ;; message about multiple packages in a directory doesn't come with a
   9364         ;; line number, so inject a fake one.
   9365         (setf (flycheck-error-line error) 1)))
   9366     errors)
   9367   :modes (go-mode go-ts-mode)
   9368   :predicate (lambda ()
   9369                (and (flycheck-buffer-saved-p)
   9370                     (not (string-suffix-p "_test.go" (buffer-file-name)))))
   9371   :next-checkers ((warning . go-errcheck)
   9372                   (warning . go-unconvert)
   9373                   (warning . go-staticcheck)))
   9374 
   9375 (flycheck-define-checker go-test
   9376   "A Go syntax and type checker using the `go test' command.
   9377 
   9378 Requires Go 1.6 or newer.  See URL `https://golang.org/cmd/go'."
   9379   :command ("go" "test"
   9380             (option-flag "-i" flycheck-go-build-install-deps)
   9381             (option-list "-tags=" flycheck-go-build-tags concat)
   9382             "-c" "-o" null-device)
   9383   :error-patterns
   9384   ((error line-start (file-name) ":" line ":"
   9385           (optional column ":") " "
   9386           (message (one-or-more not-newline)
   9387                    (zero-or-more "\n\t" (one-or-more not-newline)))
   9388           line-end))
   9389   :modes (go-mode go-ts-mode)
   9390   :predicate
   9391   (lambda () (and (flycheck-buffer-saved-p)
   9392                   (string-suffix-p "_test.go" (buffer-file-name))))
   9393   :next-checkers ((warning . go-errcheck)
   9394                   (warning . go-unconvert)
   9395                   (warning . go-staticcheck)))
   9396 
   9397 (flycheck-define-checker go-errcheck
   9398   "A Go checker for unchecked errors.
   9399 
   9400 Requires errcheck newer than commit 8515d34 (Aug 28th, 2015).
   9401 
   9402 See URL `https://github.com/kisielk/errcheck'."
   9403   :command ("errcheck"
   9404             "-abspath"
   9405             (option-list "-tags=" flycheck-go-build-tags concat)
   9406             ".")
   9407   :error-patterns
   9408   ((warning line-start
   9409             (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t")
   9410             (message)
   9411             line-end))
   9412   :error-filter
   9413   (lambda (errors)
   9414     (let ((errors (flycheck-sanitize-errors errors)))
   9415       (dolist (err errors)
   9416         (when-let (message (flycheck-error-message err))
   9417           ;; Improve the messages reported by errcheck to make them more clear.
   9418           (setf (flycheck-error-message err)
   9419                 (format "Ignored `error` returned from `%s`" message)))))
   9420     errors)
   9421   :modes (go-mode go-ts-mode)
   9422   :predicate (lambda () (flycheck-buffer-saved-p))
   9423   :next-checkers ((warning . go-unconvert)
   9424                   (warning . go-staticcheck)))
   9425 
   9426 (flycheck-define-checker go-unconvert
   9427   "A Go checker looking for unnecessary type conversions.
   9428 
   9429 See URL `https://github.com/mdempsky/unconvert'."
   9430   :command ("unconvert" ".")
   9431   :error-patterns
   9432   ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
   9433   :modes (go-mode go-ts-mode)
   9434   :predicate (lambda () (flycheck-buffer-saved-p)))
   9435 
   9436 (flycheck-define-checker go-staticcheck
   9437   "A Go checker that performs static analysis and linting using
   9438 the `staticcheck' command.
   9439 
   9440 `staticcheck' is explicitly fully compatible with \"the last two
   9441 versions of go\". `staticheck' can target earlier versions (with
   9442 limited features) if `flycheck-go-version' is set. See URL
   9443 `https://staticcheck.io/'."
   9444   :command ("staticcheck" "-f" "json"
   9445             (option-list "-tags" flycheck-go-build-tags concat)
   9446             (option "-go" flycheck-go-version))
   9447 
   9448   :error-parser flycheck-parse-go-staticcheck
   9449   :modes (go-mode go-ts-mode))
   9450 
   9451 (flycheck-define-checker groovy
   9452   "A groovy syntax checker using groovy compiler API.
   9453 
   9454 See URL `https://www.groovy-lang.org'."
   9455   :command ("groovy" "-e"
   9456             "import org.codehaus.groovy.control.*
   9457 
   9458 unit = new CompilationUnit()
   9459 unit.addSource(\"input\", System.in)
   9460 
   9461 try {
   9462     unit.compile(Phases.CONVERSION)
   9463 } catch (MultipleCompilationErrorsException e) {
   9464     e.errorCollector.write(new PrintWriter(System.out, true), null)
   9465 }")
   9466   :standard-input t
   9467   :error-patterns
   9468   ((error line-start "input: " line ":" (message)
   9469           " @ line " line ", column " column "." line-end))
   9470   :modes groovy-mode)
   9471 
   9472 (flycheck-define-checker haml
   9473   "A Haml syntax checker using the Haml compiler.
   9474 
   9475 See URL `https://haml.info'."
   9476   :command ("haml" "-c" "--stdin")
   9477   :standard-input t
   9478   :error-patterns
   9479   ((error line-start "Syntax error on line " line ": " (message) line-end)
   9480    (error line-start ":" line ": syntax error, " (message) line-end))
   9481   :modes haml-mode)
   9482 
   9483 (flycheck-define-checker haml-lint
   9484   "HAML-Lint style checker.
   9485 
   9486 See URL `https://github.com/sds/haml-lint'."
   9487   :command ("haml-lint" "--no-color" "--no-summary" source)
   9488   :error-patterns
   9489   ((error line-start (file-name) ":" line " [E]" (message) line-end)
   9490    (warning line-start (file-name) ":" line " [W]" (message) line-end))
   9491   :modes haml-mode)
   9492 
   9493 (flycheck-define-checker handlebars
   9494   "A Handlebars syntax checker using the Handlebars compiler.
   9495 
   9496 See URL `https://handlebarsjs.com/'."
   9497   :command ("handlebars" "-i-")
   9498   :standard-input t
   9499   :error-patterns
   9500   ((error line-start
   9501           "Error: Parse error on line " line ":" (optional "\r") "\n"
   9502           (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n"
   9503           (message) line-end))
   9504   :modes (handlebars-mode handlebars-sgml-mode web-mode)
   9505   :predicate
   9506   (lambda ()
   9507     (if (eq major-mode 'web-mode)
   9508         ;; Check if this is a handlebars file since web-mode does not store the
   9509         ;; non-canonical engine name
   9510         (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps))
   9511                (pattern (cdr (assoc "handlebars" regexp-alist))))
   9512           (and pattern (buffer-file-name)
   9513                (string-match-p pattern (buffer-file-name))))
   9514       t)))
   9515 
   9516 (defconst flycheck-haskell-module-re
   9517   (rx line-start (zero-or-more (or "\n" (any space)))
   9518       "module" (one-or-more (or "\n" (any space)))
   9519       (group (one-or-more (not (any space "(" "\n")))))
   9520   "Regular expression for a Haskell module name.")
   9521 
   9522 (flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc)
   9523   :package-version '(flycheck . "0.22"))
   9524 
   9525 (flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc
   9526   "Whether to enable nix support in stack.
   9527 
   9528 When non-nil, stack will append '--nix' flag to any call."
   9529   :type 'boolean
   9530   :safe #'booleanp
   9531   :package-version '(flycheck . "26"))
   9532 
   9533 (flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc
   9534   "Override project stack.yaml file.
   9535 
   9536 The value of this variable is a file path that refers to a yaml
   9537 file for the current stack project. Relative file paths are
   9538 resolved against the checker's working directory. When non-nil,
   9539 stack will get overridden value via `--stack-yaml'."
   9540   :type '(choice (const :tag "Unspecified" nil)
   9541                  (file :tag "Project file"))
   9542   :safe #'flycheck-string-or-nil-p
   9543   :package-version '(flycheck . "32"))
   9544 
   9545 (flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc
   9546   "Whether to disable the user package database in GHC.
   9547 
   9548 When non-nil, disable the user package database in GHC, via
   9549 `-no-user-package-db'."
   9550   :type 'boolean
   9551   :safe #'booleanp
   9552   :package-version '(flycheck . "0.16"))
   9553 
   9554 (flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc
   9555   "Additional module databases for GHC.
   9556 
   9557 The value of this variable is a list of strings, where each
   9558 string is a directory of a package database.  Each package
   9559 database is given to GHC via `-package-db'."
   9560   :type '(repeat (directory :tag "Package database"))
   9561   :safe #'flycheck-string-list-p
   9562   :package-version '(flycheck . "0.16"))
   9563 
   9564 (flycheck-def-option-var flycheck-ghc-search-path nil
   9565                          (haskell-stack-ghc haskell-ghc)
   9566   "Module search path for (Stack) GHC.
   9567 
   9568 The value of this variable is a list of strings, where each
   9569 string is a directory containing Haskell modules.  Each directory
   9570 is added to the GHC search path via `-i'."
   9571   :type '(repeat (directory :tag "Module directory"))
   9572   :safe #'flycheck-string-list-p
   9573   :package-version '(flycheck . "0.16"))
   9574 
   9575 (flycheck-def-option-var flycheck-ghc-language-extensions nil
   9576                          (haskell-stack-ghc haskell-ghc)
   9577   "Language extensions for (Stack) GHC.
   9578 
   9579 The value of this variable is a list of strings, where each
   9580 string is a Haskell language extension, as in the LANGUAGE
   9581 pragma.  Each extension is enabled via `-X'."
   9582   :type '(repeat (string :tag "Language extension"))
   9583   :safe #'flycheck-string-list-p
   9584   :package-version '(flycheck . "0.19"))
   9585 
   9586 (defvar flycheck-haskell-ghc-cache-directory nil
   9587   "The cache directory for `ghc' output.")
   9588 
   9589 (defun flycheck-haskell-ghc-cache-directory ()
   9590   "Get the cache location for `ghc' output.
   9591 
   9592 If no cache directory exists yet, create one and return it.
   9593 Otherwise return the previously used cache directory."
   9594   (setq flycheck-haskell-ghc-cache-directory
   9595         (or flycheck-haskell-ghc-cache-directory
   9596             (make-temp-file "flycheck-haskell-ghc-cache" 'directory))))
   9597 
   9598 (defun flycheck--locate-dominating-file-matching (directory regexp)
   9599   "Search for a file in directory hierarchy starting at DIRECTORY.
   9600 
   9601 Look up the directory hierarchy from DIRECTORY for a directory
   9602 containing a file that matches REGEXP."
   9603   (locate-dominating-file
   9604    directory
   9605    (lambda (dir)
   9606      (directory-files dir nil regexp t))))
   9607 
   9608 (defun flycheck-haskell--find-stack-default-directory ()
   9609   "Find a directory to run haskell-stack-ghc.
   9610 
   9611 Return a parent directory with a stack*.y[a]ml file, or the
   9612 directory returned by \"stack path --project-root\"."
   9613   (or
   9614    (when (buffer-file-name)
   9615      (flycheck--locate-dominating-file-matching
   9616       (file-name-directory (buffer-file-name))
   9617       (rx "stack" (* any) "." (or "yml" "yaml") eos)))
   9618    (when-let* ((stack (funcall flycheck-executable-find "stack"))
   9619                (output (ignore-errors
   9620                          (process-lines stack
   9621                                         "--no-install-ghc"
   9622                                         "path" "--project-root")))
   9623                (stack-dir (car output)))
   9624      (and (file-directory-p stack-dir) stack-dir))))
   9625 
   9626 (defun flycheck-haskell--ghc-find-default-directory (_checker)
   9627   "Find a parent directory containing a cabal or package.yaml file."
   9628   (when (buffer-file-name)
   9629     (flycheck--locate-dominating-file-matching
   9630      (file-name-directory (buffer-file-name))
   9631      "\\.cabal\\'\\|\\`package\\.yaml\\'")))
   9632 
   9633 (flycheck-define-checker haskell-stack-ghc
   9634   "A Haskell syntax and type checker using `stack ghc'.
   9635 
   9636 See URL `https://github.com/commercialhaskell/stack'."
   9637   :command ("stack"
   9638             "--no-install-ghc"
   9639             (option "--stack-yaml" flycheck-ghc-stack-project-file)
   9640             (option-flag "--nix" flycheck-ghc-stack-use-nix)
   9641             "ghc" "--" "-Wall" "-no-link"
   9642             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
   9643             (option-list "-X" flycheck-ghc-language-extensions concat)
   9644             (option-list "-i" flycheck-ghc-search-path concat)
   9645             (eval (concat
   9646                    "-i"
   9647                    (flycheck-module-root-directory
   9648                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
   9649             (eval flycheck-ghc-args)
   9650             "-x" (eval
   9651                   (pcase major-mode
   9652                     (`haskell-mode "hs")
   9653                     (`haskell-literate-mode "lhs")))
   9654             source)
   9655   :error-patterns
   9656   ((warning line-start (file-name) ":" line ":" column ":"
   9657             (or " " "\n    ") (in "Ww") "arning:"
   9658             (optional " " "[" (id (one-or-more not-newline)) "]")
   9659             (optional "\n")
   9660             (message
   9661              (one-or-more " ") (one-or-more not-newline)
   9662              (zero-or-more "\n"
   9663                            (one-or-more " ")
   9664                            (one-or-more (not (any ?\n ?|)))))
   9665             line-end)
   9666    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
   9667           (optional " " "[" (id (one-or-more not-newline)) "]")
   9668           (or (message (one-or-more not-newline))
   9669               (and "\n"
   9670                    (message
   9671                     (one-or-more " ") (one-or-more not-newline)
   9672                     (zero-or-more "\n"
   9673                                   (one-or-more " ")
   9674                                   (one-or-more (not (any ?\n ?|)))))))
   9675           line-end))
   9676   :error-filter
   9677   (lambda (errors)
   9678     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
   9679   :modes (haskell-mode haskell-literate-mode)
   9680   :next-checkers ((warning . haskell-hlint))
   9681   :working-directory (lambda (_)
   9682                        (flycheck-haskell--find-stack-default-directory))
   9683   :enabled flycheck-haskell--find-stack-default-directory
   9684   :verify (lambda (_)
   9685             (let* ((stack (flycheck-haskell--find-stack-default-directory)))
   9686               (list
   9687                (flycheck-verification-result-new
   9688                 :label "stack config"
   9689                 :message (or stack "Not found")
   9690                 :face (if stack 'success '(bold error)))))))
   9691 
   9692 (flycheck-define-checker haskell-ghc
   9693   "A Haskell syntax and type checker using ghc.
   9694 
   9695 See URL `https://www.haskell.org/ghc/'."
   9696   :command ("ghc" "-Wall" "-no-link"
   9697             "-outputdir" (eval (flycheck-haskell-ghc-cache-directory))
   9698             (option-flag "-no-user-package-db"
   9699                          flycheck-ghc-no-user-package-database)
   9700             (option-list "-package-db" flycheck-ghc-package-databases)
   9701             (option-list "-i" flycheck-ghc-search-path concat)
   9702             ;; Include the parent directory of the current module tree, to
   9703             ;; properly resolve local imports
   9704             (eval (concat
   9705                    "-i"
   9706                    (flycheck-module-root-directory
   9707                     (flycheck-find-in-buffer flycheck-haskell-module-re))))
   9708             (option-list "-X" flycheck-ghc-language-extensions concat)
   9709             (eval flycheck-ghc-args)
   9710             "-x" (eval
   9711                   (pcase major-mode
   9712                     (`haskell-mode "hs")
   9713                     (`haskell-literate-mode "lhs")))
   9714             source)
   9715   :error-patterns
   9716   ((warning line-start (file-name) ":" line ":" column ":"
   9717             (or " " "\n    ") (in "Ww") "arning:"
   9718             (optional " " "[" (id (one-or-more not-newline)) "]")
   9719             (optional "\n")
   9720             (message
   9721              (one-or-more " ") (one-or-more not-newline)
   9722              (zero-or-more "\n"
   9723                            (one-or-more " ")
   9724                            (one-or-more (not (any ?\n ?|)))))
   9725             line-end)
   9726    (error line-start (file-name) ":" line ":" column ":" (optional " error:")
   9727           (optional " " "[" (id (one-or-more not-newline)) "]")
   9728           (or (message (one-or-more not-newline))
   9729               (and "\n"
   9730                    (message
   9731                     (one-or-more " ") (one-or-more not-newline)
   9732                     (zero-or-more "\n"
   9733                                   (one-or-more " ")
   9734                                   (one-or-more (not (any ?\n ?|)))))))
   9735           line-end))
   9736   :error-filter
   9737   (lambda (errors)
   9738     (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
   9739   :modes (haskell-mode haskell-literate-mode)
   9740   :next-checkers ((warning . haskell-hlint))
   9741   :working-directory flycheck-haskell--ghc-find-default-directory)
   9742 
   9743 (flycheck-def-config-file-var flycheck-hlintrc haskell-hlint ".hlint.yaml")
   9744 
   9745 (flycheck-def-args-var flycheck-hlint-args haskell-hlint
   9746   :package-version '(flycheck . "0.25"))
   9747 
   9748 (flycheck-def-option-var flycheck-hlint-language-extensions
   9749     nil haskell-hlint
   9750   "Extensions list to enable for hlint.
   9751 
   9752 The value of this variable is a list of strings, where each
   9753 string is a name of extension to enable in
   9754 hlint (e.g. \"QuasiQuotes\")."
   9755   :type '(repeat :tag "Extensions" (string :tag "Extension"))
   9756   :safe #'flycheck-string-list-p
   9757   :package-version '(flycheck . "0.24"))
   9758 
   9759 (flycheck-def-option-var flycheck-hlint-ignore-rules
   9760     nil haskell-hlint
   9761   "Ignore rules list for hlint checks.
   9762 
   9763 The value of this variable is a list of strings, where each
   9764 string is an ignore rule (e.g. \"Use fmap\")."
   9765   :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule"))
   9766   :safe #'flycheck-string-list-p
   9767   :package-version '(flycheck . "0.24"))
   9768 
   9769 (flycheck-def-option-var flycheck-hlint-hint-packages
   9770     nil haskell-hlint
   9771   "Hint packages to include for hlint checks.
   9772 
   9773 The value of this variable is a list of strings, where each
   9774 string is a default hint package (e.g. (\"Generalise\"
   9775 \"Default\" \"Dollar\"))."
   9776   :type '(repeat :tag "Hint packages" (string :tag "Hint package"))
   9777   :safe #'flycheck-string-list-p
   9778   :package-version '(flycheck . "0.24"))
   9779 
   9780 (flycheck-define-checker haskell-hlint
   9781   "A Haskell style checker using hlint.
   9782 
   9783 See URL `https://github.com/ndmitchell/hlint'."
   9784   :command ("hlint"
   9785             "--no-exit-code"
   9786             (option-list "-X" flycheck-hlint-language-extensions concat)
   9787             (option-list "-i=" flycheck-hlint-ignore-rules concat)
   9788             (option-list "-h" flycheck-hlint-hint-packages concat)
   9789             (config-file "-h" flycheck-hlintrc)
   9790             (eval flycheck-hlint-args)
   9791             source-inplace)
   9792   :error-patterns
   9793   ((info line-start
   9794          (file-name) ":"
   9795          (or (seq line ":" column (optional "-" end-column))
   9796              (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9797          ": Suggestion: "
   9798          (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9799          line-end)
   9800    (warning line-start
   9801             (file-name) ":"
   9802             (or (seq line ":" column (optional "-" end-column))
   9803                 (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9804             ": Warning: "
   9805             (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9806             line-end)
   9807    (error line-start
   9808           (file-name) ":"
   9809           (or (seq line ":" column (optional "-" end-column))
   9810               (seq "(" line "," column ")-(" end-line "," end-column ")"))
   9811           ": Error: "
   9812           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
   9813           line-end))
   9814   :modes (haskell-mode haskell-literate-mode))
   9815 
   9816 (flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc")
   9817 
   9818 (flycheck-define-checker html-tidy
   9819   "A HTML syntax and style checker using Tidy.
   9820 
   9821 See URL `https://github.com/htacg/tidy-html5'."
   9822   :command ("tidy" (config-file "-config" flycheck-tidyrc)
   9823             "-lang" "en"
   9824             "-e" "-q")
   9825   :standard-input t
   9826   :error-patterns
   9827   ((error line-start
   9828           "line " line
   9829           " column " column
   9830           " - Error: " (message) line-end)
   9831    (warning line-start
   9832             "line " line
   9833             " column " column
   9834             " - Warning: " (message) line-end))
   9835   :modes (html-mode mhtml-mode nxhtml-mode))
   9836 
   9837 (flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc")
   9838 
   9839 (flycheck-def-option-var flycheck-jshint-extract-javascript nil
   9840                          javascript-jshint
   9841   "Whether jshint should extract Javascript from HTML.
   9842 
   9843 If nil no extract rule is given to jshint.  If `auto' only
   9844 extract Javascript if a HTML file is detected.  If `always' or
   9845 `never' extract Javascript always or never respectively.
   9846 
   9847 Refer to the jshint manual at the URL
   9848 `https://jshint.com/docs/cli/#flags' for more information."
   9849   :type
   9850   '(choice (const :tag "No extraction rule" nil)
   9851            (const :tag "Try to extract Javascript when detecting HTML files"
   9852                   auto)
   9853            (const :tag "Always try to extract Javascript" always)
   9854            (const :tag "Never try to extract Javascript" never))
   9855   :safe #'symbolp
   9856   :package-version '(flycheck . "26"))
   9857 
   9858 (flycheck-define-checker javascript-jshint
   9859   "A Javascript syntax and style checker using jshint.
   9860 
   9861 See URL `https://www.jshint.com'."
   9862   :command ("jshint" "--reporter=checkstyle"
   9863             "--filename" source-original
   9864             (config-file "--config" flycheck-jshintrc)
   9865             (option "--extract=" flycheck-jshint-extract-javascript
   9866                     concat flycheck-option-symbol)
   9867             "-")
   9868   :standard-input t
   9869   :error-parser flycheck-parse-checkstyle
   9870   :error-filter
   9871   (lambda (errors)
   9872     (flycheck-remove-error-file-names
   9873      "stdin" (flycheck-dequalify-error-ids errors)))
   9874   :modes (js-mode js2-mode js3-mode rjsx-mode js-ts-mode))
   9875 
   9876 (flycheck-def-args-var flycheck-eslint-args javascript-eslint
   9877   :package-version '(flycheck . "32"))
   9878 
   9879 (flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint
   9880   "A list of directories with custom rules for ESLint.
   9881 
   9882 The value of this variable is a list of strings, where each
   9883 string is a directory with custom rules for ESLint.
   9884 
   9885 Refer to the ESLint manual at URL
   9886 `https://eslint.org/docs/user-guide/command-line-interface#--rulesdir'
   9887 for more information about the custom directories."
   9888   :type '(repeat (directory :tag "Custom rules directory"))
   9889   :safe #'flycheck-string-list-p
   9890   :package-version '(flycheck . "29"))
   9891 
   9892 (defun flycheck-eslint-config-exists-p ()
   9893   "Whether there is a valid eslint config for the current buffer."
   9894   (eql 0 (flycheck-call-checker-process
   9895           'javascript-eslint nil nil nil
   9896           "--print-config" (or buffer-file-name "index.js"))))
   9897 
   9898 (defun flycheck-parse-eslint (output checker buffer)
   9899   "Parse ESLint errors/warnings from JSON OUTPUT.
   9900 
   9901 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
   9902 the BUFFER that was checked respectively.
   9903 
   9904 See URL `https://eslint.org' for more information about ESLint."
   9905   (mapcar (lambda (err)
   9906             (let-alist err
   9907               (flycheck-error-new-at
   9908                .line
   9909                .column
   9910                (pcase .severity
   9911                  (2 'error)
   9912                  (1 'warning)
   9913                  (_ 'warning))
   9914                .message
   9915                :id .ruleId
   9916                :checker checker
   9917                :buffer buffer
   9918                :filename (buffer-file-name buffer)
   9919                :end-line .endLine
   9920                :end-column .endColumn)))
   9921           (let-alist (caar (flycheck-parse-json output))
   9922             .messages)))
   9923 
   9924 (defun flycheck-eslint--find-working-directory (_checker)
   9925   "Look for a working directory to run ESLint CHECKER in.
   9926 
   9927 This will be the directory that contains the `node_modules'
   9928 directory.  If no such directory is found in the directory
   9929 hierarchy, it looks first for `.eslintignore' and then for
   9930 `.eslintrc' files to detect the project root."
   9931   (let* ((regex-config (concat "\\`\\.eslintrc"
   9932                                "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'")))
   9933     (when buffer-file-name
   9934       (or (locate-dominating-file buffer-file-name "node_modules")
   9935           (locate-dominating-file buffer-file-name ".eslintignore")
   9936           (locate-dominating-file
   9937            (file-name-directory buffer-file-name)
   9938            (lambda (directory)
   9939              (> (length (directory-files directory nil regex-config t)) 0)))))))
   9940 
   9941 (flycheck-define-checker javascript-eslint
   9942   "A Javascript syntax and style checker using eslint.
   9943 
   9944 See URL `https://eslint.org/'."
   9945   :command ("eslint" "--format=json"
   9946             (option-list "--rulesdir" flycheck-eslint-rules-directories)
   9947             (eval flycheck-eslint-args)
   9948             "--stdin" "--stdin-filename" source-original)
   9949   :standard-input t
   9950   :error-parser flycheck-parse-eslint
   9951   :enabled (lambda () (flycheck-eslint-config-exists-p))
   9952   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
   9953                   typescript-mode js-ts-mode typescript-ts-mode tsx-ts-mode)
   9954   :working-directory flycheck-eslint--find-working-directory
   9955   :verify
   9956   (lambda (_)
   9957     (let* ((default-directory
   9958              (flycheck-compute-working-directory 'javascript-eslint))
   9959            (have-config (flycheck-eslint-config-exists-p)))
   9960       (list
   9961        (flycheck-verification-result-new
   9962         :label "config file"
   9963         :message (if have-config "found" "missing or incorrect")
   9964         :face (if have-config 'success '(bold error))))))
   9965   :error-explainer
   9966   (lambda (err)
   9967     (let ((error-code (flycheck-error-id err))
   9968           (url "https://eslint.org/docs/rules/%s"))
   9969       (and error-code
   9970            ;; skip non-builtin rules
   9971            (not ;; `seq-contains-p' is only in seq >= 2.21
   9972             (with-no-warnings (seq-contains error-code ?/)))
   9973            `(url . ,(format url error-code))))))
   9974 
   9975 (flycheck-define-checker javascript-standard
   9976   "A Javascript code and style checker for the (Semi-)Standard Style.
   9977 
   9978 This checker works with `standard' and `semistandard', defaulting
   9979 to the former.  To use it with the latter, set
   9980 `flycheck-javascript-standard-executable' to `semistandard'.
   9981 
   9982 See URL `https://github.com/standard/standard' and URL
   9983 `https://github.com/Flet/semistandard'."
   9984   :command ("standard" "--stdin")
   9985   :standard-input t
   9986   :error-patterns
   9987   ((error line-start "  <text>:" line ":" column ":" (message) line-end))
   9988   :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode
   9989                   js-ts-mode))
   9990 
   9991 (flycheck-define-checker json-jsonlint
   9992   "A JSON syntax and style checker using jsonlint.
   9993 
   9994 See URL `https://github.com/zaach/jsonlint'."
   9995   ;; We can't use standard input for jsonlint, because it doesn't output errors
   9996   ;; anymore when using -c -q with standard input :/
   9997   :command ("jsonlint" "-c" "-q" source)
   9998   :error-patterns
   9999   ((error line-start
  10000           (file-name)
  10001           ": line " line
  10002           ", col " column ", "
  10003           (message) line-end))
  10004   :error-filter
  10005   (lambda (errors)
  10006     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
  10007   :modes (json-mode js-json-mode json-ts-mode))
  10008 
  10009 (flycheck-define-checker json-python-json
  10010   "A JSON syntax checker using Python json.tool module.
  10011 
  10012 See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'."
  10013   :command ("python3" "-m" "json.tool" source
  10014             ;; Send the pretty-printed output to the null device
  10015             null-device)
  10016   :error-patterns
  10017   ((error line-start
  10018           (message) ": line " line " column " column
  10019           ;; Ignore the rest of the line which shows the char position.
  10020           (one-or-more not-newline)
  10021           line-end))
  10022   :modes (json-mode js-json-mode json-ts-mode)
  10023   ;; The JSON parser chokes if the buffer is empty and has no JSON inside
  10024   :predicate flycheck-buffer-nonempty-p)
  10025 
  10026 (flycheck-define-checker json-jq
  10027   "JSON checker using the jq tool.
  10028 
  10029 This checker accepts multiple consecutive JSON values in a
  10030 single input, which is useful for jsonlines data.
  10031 
  10032 See URL `https://stedolan.github.io/jq/'."
  10033   :command ("jq" "." source null-device)
  10034   ;; Example error message:
  10035   ;;   parse error: Expected another key-value pair at line 3, column 1
  10036   :error-patterns
  10037   ((error line-start
  10038           (optional "parse error: ")
  10039           (message) "at line " line ", column " column
  10040           (zero-or-more not-newline) line-end))
  10041   :modes (json-mode js-json-mode json-ts-mode))
  10042 
  10043 (flycheck-define-checker jsonnet
  10044   "A Jsonnet syntax checker using the jsonnet binary.
  10045 
  10046 See URL `https://jsonnet.org'."
  10047   :command ("jsonnet" source-inplace)
  10048   :error-patterns
  10049   ((error line-start "STATIC ERROR: " (file-name) ":"
  10050           (or (seq line ":" column (zero-or-one (seq "-" end-column)))
  10051               (seq "(" line ":" column ")" "-"
  10052                    "(" end-line ":" end-column ")"))
  10053           ": " (message) line-end)
  10054    (error line-start "RUNTIME ERROR: " (message) "\n"
  10055           (? "\t" (file-name) ":" ;; first line of the backtrace
  10056              (or (seq line ":" column (zero-or-one (seq "-" end-column)))
  10057                  (seq "(" line ":" column ")" "-"
  10058                       "(" end-line ":" end-column ")")))))
  10059   :error-filter
  10060   (lambda (errs)
  10061     ;; Some errors are missing line numbers. See URL
  10062     ;; `https://github.com/google/jsonnet/issues/786'.
  10063     (dolist (err errs)
  10064       (unless (flycheck-error-line err)
  10065         (setf (flycheck-error-line err) 1)))
  10066     (flycheck-sanitize-errors errs))
  10067   :modes jsonnet-mode)
  10068 
  10069 (flycheck-define-checker less
  10070   "A LESS syntax checker using lessc.
  10071 
  10072 Requires lessc 1.4 or newer.
  10073 
  10074 See URL `https://lesscss.org'."
  10075   :command ("lessc" "--lint" "--no-color"
  10076             "-")
  10077   :standard-input t
  10078   :error-patterns
  10079   ((error line-start (one-or-more word) ":"
  10080           (message)
  10081           " in - on line " line
  10082           ", column " column ":"
  10083           line-end))
  10084   :modes less-css-mode)
  10085 
  10086 (flycheck-define-checker less-stylelint
  10087   "A LESS syntax and style checker using stylelint.
  10088 
  10089 See URL `https://stylelint.io/'."
  10090   :command ("stylelint"
  10091             (eval flycheck-stylelint-args)
  10092             (option-flag "--quiet" flycheck-stylelint-quiet)
  10093             (config-file "--config" flycheck-stylelintrc))
  10094   :standard-input t
  10095   :verify (lambda (_) (flycheck--stylelint-verify 'less-stylelint))
  10096   :error-parser flycheck-parse-stylelint
  10097   :predicate flycheck-buffer-nonempty-p
  10098   :modes (less-css-mode))
  10099 
  10100 (flycheck-define-checker llvm-llc
  10101   "Flycheck LLVM IR checker using llc.
  10102 
  10103 See URL `https://llvm.org/docs/CommandGuide/llc.html'."
  10104   :command ("llc" "-o" null-device source)
  10105   :error-patterns
  10106   ((error line-start
  10107           ;; llc prints the executable path
  10108           (zero-or-one (minimal-match (one-or-more not-newline)) ": ")
  10109           (file-name) ":" line ":" column ": error: " (message)
  10110           line-end))
  10111   :error-filter
  10112   (lambda (errors)
  10113     ;; sanitize errors occurring in inline assembly
  10114     (flycheck-sanitize-errors
  10115      (flycheck-remove-error-file-names "<inline asm>" errors)))
  10116   :modes llvm-mode)
  10117 
  10118 (flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc")
  10119 
  10120 (flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck
  10121   "The standards to use in luacheck.
  10122 
  10123 The value of this variable is either a list of strings denoting
  10124 the standards to use, or nil to pass nothing to luacheck.  When
  10125 non-nil, pass the standards via one or more `--std' options."
  10126   :type '(choice (const :tag "Default" nil)
  10127                  (repeat :tag "Custom standards"
  10128                          (string :tag "Standard name")))
  10129   :safe #'flycheck-string-list-p)
  10130 (make-variable-buffer-local 'flycheck-luacheck-standards)
  10131 
  10132 (flycheck-define-checker lua-luacheck
  10133   "A Lua syntax checker using luacheck.
  10134 
  10135 See URL `https://github.com/mpeterv/luacheck'."
  10136   :command ("luacheck"
  10137             "--formatter" "plain"
  10138             "--codes"                   ; Show warning codes
  10139             "--no-color"
  10140             (option-list "--std" flycheck-luacheck-standards)
  10141             (config-file "--config" flycheck-luacheckrc)
  10142             "--filename" source-original
  10143             ;; Read from standard input
  10144             "-")
  10145   :standard-input t
  10146   :error-patterns
  10147   ((warning line-start
  10148             (optional (file-name))
  10149             ":" line ":" column
  10150             ": (" (id "W" (one-or-more digit)) ") "
  10151             (message) line-end)
  10152    (error line-start
  10153           (optional (file-name))
  10154           ":" line ":" column ":"
  10155           ;; `luacheck' before 0.11.0 did not output codes for errors, hence
  10156           ;; the ID is optional here
  10157           (optional " (" (id "E" (one-or-more digit)) ") ")
  10158           (message) line-end))
  10159   :modes (lua-mode lua-ts-mode))
  10160 
  10161 (flycheck-define-checker lua
  10162   "A Lua syntax checker using the Lua compiler.
  10163 
  10164 See URL `https://www.lua.org/'."
  10165   :command ("luac" "-p" "-")
  10166   :standard-input t
  10167   :error-patterns
  10168   ((error line-start
  10169           ;; Skip the name of the luac executable.
  10170           (minimal-match (zero-or-more not-newline))
  10171           ": stdin:" line ": " (message) line-end))
  10172   :modes (lua-mode lua-ts-mode))
  10173 
  10174 (flycheck-define-checker opam
  10175   "A Opam syntax and style checker using opam lint.
  10176 
  10177 See URL `https://opam.ocaml.org/doc/man/opam-lint.html'."
  10178   :command ("opam" "lint" "-")
  10179   :standard-input t
  10180   :error-patterns
  10181   ((error line-start                    ; syntax error
  10182           (one-or-more space) "error  " (id ?2)
  10183           ": File format error"
  10184           (or (and " at line " line ", column " column ": " (message))
  10185               (and ": " (message)))
  10186           line-end)
  10187    (error line-start
  10188           (one-or-more space) "error  " (id ?3)
  10189           (minimal-match (zero-or-more not-newline))
  10190           "at line " line ", column " column ": " (message)
  10191           line-end)
  10192    (error line-start
  10193           (one-or-more space) "error " (id (one-or-more num))
  10194           ": " (message (one-or-more not-newline))
  10195           line-end)
  10196    (warning line-start
  10197             (one-or-more space) "warning " (id (one-or-more num))
  10198             ": " (message)
  10199             line-end))
  10200   :error-filter
  10201   (lambda (errors)
  10202     (flycheck-increment-error-columns
  10203      (flycheck-fill-empty-line-numbers errors)))
  10204   :modes tuareg-opam-mode)
  10205 
  10206 (flycheck-def-option-var flycheck-perl-include-path nil perl
  10207   "A list of include directories for Perl.
  10208 
  10209 The value of this variable is a list of strings, where each
  10210 string is a directory to add to the include path of Perl.
  10211 Relative paths are relative to the file being checked."
  10212   :type '(repeat (directory :tag "Include directory"))
  10213   :safe #'flycheck-string-list-p
  10214   :package-version '(flycheck . "0.24"))
  10215 
  10216 (flycheck-def-option-var flycheck-perl-module-list nil perl
  10217   "A list of modules to use for Perl.
  10218 
  10219 The value of this variable is a list of strings, where each
  10220 string is a module to `use' in Perl."
  10221   :type '(repeat :tag "Module")
  10222   :safe #'flycheck-string-list-p
  10223   :package-version '(flycheck . "32"))
  10224 
  10225 (flycheck-define-checker perl
  10226   "A Perl syntax checker using the Perl interpreter.
  10227 
  10228 See URL `https://www.perl.org'."
  10229   :command ("perl" "-w" "-c"
  10230             (option-list "-I" flycheck-perl-include-path)
  10231             (option-list "-M" flycheck-perl-module-list concat))
  10232   :standard-input t
  10233   :error-patterns
  10234   ((error line-start (minimal-match (message))
  10235           " at - line " line
  10236           (or "." (and ", " (zero-or-more not-newline))) line-end))
  10237   :modes (perl-mode cperl-mode)
  10238   :next-checkers (perl-perlcritic))
  10239 
  10240 (flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic
  10241   "The message severity for Perl Critic.
  10242 
  10243 The value of this variable is a severity level as integer, for
  10244 the `--severity' option to Perl Critic."
  10245   :type '(integer :tag "Severity level")
  10246   :safe #'integerp
  10247   :package-version '(flycheck . "0.18"))
  10248 
  10249 (flycheck-def-option-var flycheck-perlcritic-theme nil perl-perlcritic
  10250   "The theme expression for Perl Critic.
  10251 
  10252 The value of this variable is passed as the `--theme' option to
  10253 `Perl::Critic'.  See the documentation of `Perl::Critic' for
  10254 details."
  10255   :type '(choice (const :tag "None" nil)
  10256                  (string :tag "Theme expression"))
  10257   :safe #'flycheck-string-or-nil-p
  10258   :package-version '(flycheck . "32-csv"))
  10259 
  10260 (flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic
  10261                               ".perlcriticrc"
  10262   :package-version '(flycheck . "26"))
  10263 
  10264 (flycheck-define-checker perl-perlcritic
  10265   "A Perl syntax checker using Perl::Critic.
  10266 
  10267 See URL `https://metacpan.org/pod/Perl::Critic'."
  10268   :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n"
  10269             (config-file "--profile" flycheck-perlcriticrc)
  10270             (option "--severity" flycheck-perlcritic-severity nil
  10271                     flycheck-option-int)
  10272             (option "--theme" flycheck-perlcritic-theme))
  10273   :standard-input t
  10274   :error-patterns
  10275   ((info line-start
  10276          "STDIN/" line "/" column "/" (any "1") "/"
  10277          (id (one-or-more (not (any "/")))) "/" (message)
  10278          line-end)
  10279    (warning line-start
  10280             "STDIN/" line "/" column "/" (any "234") "/"
  10281             (id (one-or-more (not (any "/")))) "/" (message)
  10282             line-end)
  10283    (error line-start
  10284           "STDIN/" line "/" column "/" (any "5") "/"
  10285           (id (one-or-more (not (any "/")))) "/" (message)
  10286           line-end))
  10287   :modes (cperl-mode perl-mode)
  10288   :next-checkers (perl-perlimports)
  10289 
  10290   :error-explainer
  10291   (lambda (err)
  10292     (let ((error-code (flycheck-error-id err))
  10293           (url "https://metacpan.org/pod/Perl::Critic::Policy::%s"))
  10294       (and error-code `(url . ,(format url error-code))))))
  10295 
  10296 (defun flycheck-perl-perlimports-parse-errors (output checker buffer)
  10297   "Parse perlimports json output errors from OUTPUT.
  10298 
  10299 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
  10300 the BUFFER that was checked respectively.
  10301 
  10302 See URL `https://metacpan.org/dist/App-perlimports/view/script/perlimports'
  10303 for more information about perlimports."
  10304   (mapcar (lambda (err)
  10305             (let-alist err
  10306               (flycheck-error-new-at
  10307                .location.start.line
  10308                .location.start.column
  10309                'info
  10310                (concat .module " " .reason ":"
  10311                        (with-temp-buffer
  10312                          (insert (substring .diff (string-match-p "\n" .diff)))
  10313                          (diff-mode)
  10314                          (font-lock-ensure)
  10315                          (buffer-string)))
  10316                :end-line .location.end.line
  10317                :end-column .location.end.column
  10318                :checker checker
  10319                :buffer buffer)))
  10320           (flycheck-parse-json output)))
  10321 
  10322 (flycheck-define-checker perl-perlimports
  10323   "A checker for cleaning up Perl import statements.
  10324 
  10325 See URL `https://metacpan.org/dist/App-perlimports/view/script/perlimports'."
  10326   :command ("perlimports"
  10327             "--filename" source
  10328             "--json"
  10329             "--lint"
  10330             "--no-preserve-duplicates"
  10331             "--no-preserve-unused"
  10332             "--no-tidy-whitespace"
  10333             "--read-stdin")
  10334   :standard-input t
  10335   :error-parser flycheck-perl-perlimports-parse-errors
  10336   :modes (cperl-mode perl-mode))
  10337 
  10338 (flycheck-define-checker php
  10339   "A PHP syntax checker using the PHP command line interpreter.
  10340 
  10341 See URL `https://php.net/manual/en/features.commandline.php'."
  10342   :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
  10343             "-d" "log_errors=0" source)
  10344   :error-patterns
  10345   ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " "
  10346           (message) " in " (file-name) " on line " line line-end))
  10347   :modes (php-mode php-ts-mode php+-mode)
  10348   :next-checkers ((warning . php-phpmd)
  10349                   (warning . php-phpcs)))
  10350 
  10351 (flycheck-def-option-var flycheck-phpmd-rulesets
  10352     '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode")
  10353     php-phpmd
  10354   "The rule sets for PHP Mess Detector.
  10355 
  10356 Set default rule sets and custom rule set files.
  10357 
  10358 See section \"Using multiple rule sets\" in the PHP Mess Detector
  10359 manual at URL `https://phpmd.org/documentation/index.html'."
  10360   :type '(repeat :tag "rule sets"
  10361                  (string :tag "A filename or rule set"))
  10362   :safe #'flycheck-string-list-p)
  10363 
  10364 (flycheck-define-checker php-phpmd
  10365   "A PHP style checker using PHP Mess Detector.
  10366 
  10367 See URL `https://phpmd.org/'."
  10368   :command ("phpmd" source "xml"
  10369             (eval (flycheck-option-comma-separated-list
  10370                    flycheck-phpmd-rulesets)))
  10371   :error-parser flycheck-parse-phpmd
  10372   :modes (php-mode php-ts-mode php+-mode)
  10373   :next-checkers (php-phpcs))
  10374 
  10375 (flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs
  10376   "The coding standard for PHP CodeSniffer.
  10377 
  10378 When nil, use the default standard from the global PHP
  10379 CodeSniffer configuration.  When set to a string, pass the string
  10380 to PHP CodeSniffer which will interpret it as name as a standard,
  10381 or as path to a standard specification."
  10382   :type '(choice (const :tag "Default standard" nil)
  10383                  (string :tag "Standard name or file"))
  10384   :safe #'flycheck-string-or-nil-p)
  10385 
  10386 (flycheck-define-checker php-phpcs
  10387   "A PHP style checker using PHP Code Sniffer.
  10388 
  10389 Needs PHP Code Sniffer 2.6 or newer.
  10390 
  10391 See URL `https://pear.php.net/package/PHP_CodeSniffer/'."
  10392   :command ("phpcs" "--report=checkstyle"
  10393             ;; Use -q flag to force quiet mode
  10394             ;; Quiet mode prevents errors from extra output when phpcs has
  10395             ;; been configured with show_progress enabled
  10396             "-q"
  10397             (option "--standard=" flycheck-phpcs-standard concat)
  10398             ;; Some files are not detected correctly
  10399             ;; so it is necessary to pass the extension.
  10400             (eval
  10401              (when-let* ((fname buffer-file-name)
  10402                          (ext (file-name-extension fname)))
  10403                (concat "--extensions=" ext)))
  10404 
  10405             ;; Pass original file name to phpcs.  We need to concat explicitly
  10406             ;; here, because phpcs really insists to get option and argument as
  10407             ;; a single command line argument :|
  10408             (eval (when (buffer-file-name)
  10409                     (concat "--stdin-path=" (buffer-file-name))))
  10410             ;; Read from standard input
  10411             "-")
  10412   :standard-input t
  10413   :error-parser flycheck-parse-checkstyle
  10414   :error-filter
  10415   (lambda (errors)
  10416     (flycheck-sanitize-errors
  10417      (flycheck-remove-error-file-names "STDIN" errors)))
  10418   :modes (php-mode php-ts-mode php+-mode)
  10419   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
  10420   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
  10421   :predicate flycheck-buffer-nonempty-p)
  10422 
  10423 (flycheck-define-checker php-phpcs-changed
  10424   "A PHP style checker using PHPCS-Changed.
  10425    Needs PHP Code Sniffer 2.6 or newer.
  10426    See `https://github.com/sirbrillig/phpcs-changed'."
  10427   :command ("phpcs-changed"
  10428             "--git"
  10429             "--git-base trunk"
  10430             "--git-unstaged"
  10431             (option "--standard=" flycheck-phpcs-standard concat)
  10432             (eval (buffer-file-name))
  10433             )
  10434   :standard-input t
  10435   :error-parser flycheck-parse-checkstyle
  10436   :error-filter
  10437   (lambda (errors)
  10438     (flycheck-sanitize-errors
  10439      (flycheck-remove-error-file-names "STDIN" errors)))
  10440   :modes (php-mode php+-mode)
  10441   ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
  10442   ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
  10443   :predicate flycheck-buffer-nonempty-p)
  10444 
  10445 (flycheck-define-checker processing
  10446   "Processing command line tool.
  10447 
  10448 See https://github.com/processing/processing/wiki/Command-Line"
  10449   :command ("processing-java" "--force"
  10450             ;; Don't change the order of these arguments, processing is pretty
  10451             ;; picky
  10452             (eval (concat "--sketch=" (file-name-directory (buffer-file-name))))
  10453             (eval (concat "--output=" (flycheck-temp-dir-system)))
  10454             "--build")
  10455   :error-patterns
  10456   ((error line-start (file-name) ":" line ":" column
  10457           (zero-or-more (or digit ":")) (message) line-end))
  10458   :modes processing-mode
  10459   ;; This syntax checker needs a file name
  10460   :predicate (lambda () (buffer-file-name)))
  10461 
  10462 (defun flycheck-proselint-parse-errors (output checker buffer)
  10463   "Parse proselint json output errors from OUTPUT.
  10464 
  10465 CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
  10466 the BUFFER that was checked respectively.
  10467 
  10468 See URL `https://proselint.com/' for more information about proselint."
  10469   (mapcar (lambda (err)
  10470             (let-alist err
  10471               (flycheck-error-new-at-pos
  10472                .start
  10473                (pcase .severity
  10474                  (`"suggestion" 'info)
  10475                  (`"warning"    'warning)
  10476                  (`"error"      'error)
  10477                  ;; Default to error
  10478                  (_             'error))
  10479                .message
  10480                :id .check
  10481                :buffer buffer
  10482                :checker checker
  10483                ;; See https://github.com/amperser/proselint/issues/1048
  10484                :end-pos .end)))
  10485           (let-alist (car (flycheck-parse-json output))
  10486             .data.errors)))
  10487 
  10488 (flycheck-define-checker proselint
  10489   "Flycheck checker using Proselint.
  10490 
  10491 See URL `https://proselint.com/'."
  10492   :command ("proselint" "--json" "-")
  10493   :standard-input t
  10494   :error-parser flycheck-proselint-parse-errors
  10495   :modes (text-mode markdown-mode gfm-mode message-mode org-mode))
  10496 
  10497 (flycheck-def-option-var flycheck-protoc-import-path nil protobuf-protoc
  10498   "A list of directories to resolve import directives.
  10499 
  10500 The value of this variable is a list of strings, where each
  10501 string is a directory to add to the import path.  Relative paths
  10502 are relative to the file being checked."
  10503   :type '(repeat (directory :tag "Import directory"))
  10504   :safe #'flycheck-string-list-p
  10505   :package-version '(flycheck . "32"))
  10506 
  10507 (flycheck-define-checker protobuf-protoc
  10508   "A protobuf syntax checker using the protoc compiler.
  10509 
  10510 See URL `https://developers.google.com/protocol-buffers/'."
  10511   :command ("protoc" "--error_format" "gcc"
  10512             (eval (concat "--java_out=" (flycheck-temp-dir-system)))
  10513             ;; Add the current directory to resolve imports
  10514             (eval (concat "--proto_path="
  10515                           (file-name-directory (buffer-file-name))))
  10516             ;; Add other import paths; this needs to be after the current
  10517             ;; directory to produce the right output.  See URL
  10518             ;; `https://github.com/flycheck/flycheck/pull/1655'
  10519             (option-list "--proto_path=" flycheck-protoc-import-path concat)
  10520             source-inplace)
  10521   :error-patterns
  10522   ((info line-start (file-name) ":" line ":" column
  10523          ": note: " (message) line-end)
  10524    (error line-start (file-name) ":" line ":" column
  10525           ": " (message) line-end)
  10526    (error line-start
  10527           (message "In file included from") " " (file-name) ":" line ":"
  10528           column ":" line-end))
  10529   :modes protobuf-mode
  10530   :predicate (lambda () (buffer-file-name)))
  10531 
  10532 (defun flycheck-prototool-project-root (&optional _checker)
  10533   "Return the nearest directory holding the prototool.yaml configuration."
  10534   (and buffer-file-name
  10535        (locate-dominating-file buffer-file-name "prototool.yaml")))
  10536 
  10537 (flycheck-define-checker protobuf-prototool
  10538   "A protobuf syntax checker using prototool.
  10539 
  10540 See URL `https://github.com/uber/prototool'."
  10541   :command ("prototool" "lint" source-original)
  10542   :error-patterns
  10543   ((warning line-start (file-name) ":" line ":" column ":" (message) line-end))
  10544   :modes protobuf-mode
  10545   :enabled flycheck-prototool-project-root
  10546   :predicate flycheck-buffer-saved-p)
  10547 
  10548 (flycheck-define-checker pug
  10549   "A Pug syntax checker using the pug compiler.
  10550 
  10551 See URL `https://pugjs.org/'."
  10552   :command ("pug" "-p" (eval (expand-file-name (buffer-file-name))))
  10553   :standard-input t
  10554   :error-patterns
  10555   ;; errors with includes/extends (e.g. missing files)
  10556   ((error "Error: " (message) (zero-or-more not-newline) "\n"
  10557           (zero-or-more not-newline) "at "
  10558           (zero-or-more not-newline) " line " line)
  10559    ;; error when placing anything other than a mixin or
  10560    ;; block at the top-level of an extended template
  10561    ;; also unknown filters
  10562    (error line-start "Error: " (file-name) ":"
  10563           line ":" column "\n\n" (message) line-end)
  10564    ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.)
  10565    (error line-start
  10566           (optional "Type") "Error: "  (file-name) ":"
  10567           line (optional ":" column)
  10568           (zero-or-more not-newline) "\n"
  10569           (one-or-more (or (zero-or-more not-newline) "|"
  10570                            (zero-or-more not-newline) "\n")
  10571                        (zero-or-more "-")  (zero-or-more not-newline) "|"
  10572                        (zero-or-more not-newline) "\n")
  10573           (zero-or-more not-newline) "\n"
  10574           (one-or-more
  10575            (zero-or-more not-newline) "|"
  10576            (zero-or-more not-newline) "\n")
  10577           (zero-or-more not-newline) "\n"
  10578           (message)
  10579           line-end))
  10580   :modes pug-mode)
  10581 
  10582 (flycheck-define-checker puppet-parser
  10583   "A Puppet DSL syntax checker using puppet's own parser.
  10584 
  10585 See URL `https://puppet.com/'."
  10586   :command ("puppet" "parser" "validate" "--color=false")
  10587   :standard-input t
  10588   :error-patterns
  10589   (
  10590    ;; Patterns for Puppet 4
  10591    (error line-start "Error: Could not parse for environment "
  10592           (one-or-more (in "a-z" "0-9" "_")) ":"
  10593           (message) "(line: " line ", column: " column ")" line-end)
  10594    ;; Errors from Puppet < 4
  10595    (error line-start "Error: Could not parse for environment "
  10596           (one-or-more (in "a-z" "0-9" "_")) ":"
  10597           (message (minimal-match (one-or-more anything)))
  10598           " at line " line line-end)
  10599    (error line-start
  10600           ;; Skip over the path of the Puppet executable
  10601           (minimal-match (zero-or-more not-newline))
  10602           ": Could not parse for environment " (one-or-more word)
  10603           ": " (message (minimal-match (zero-or-more anything)))
  10604           " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end))
  10605   :modes puppet-mode
  10606   :next-checkers ((warning . puppet-lint)))
  10607 
  10608 (flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint
  10609                               ".puppet-lint.rc"
  10610   :package-version '(flycheck . "26"))
  10611 
  10612 (flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint
  10613   "Disabled checkers for `puppet-lint'.
  10614 
  10615 The value of this variable is a list of strings, where each
  10616 string is the name of a check to disable (e.g. \"80chars\" or
  10617 \"double_quoted_strings\").
  10618 
  10619 See URL `https://puppet-lint.com/checks/' for a list of all checks
  10620 and their names."
  10621   :type '(repeat (string :tag "Check Name"))
  10622   :package-version '(flycheck . "26"))
  10623 
  10624 (defun flycheck-puppet-lint-disabled-arg-name (check)
  10625   "Create an argument to disable a puppetlint CHECK."
  10626   (concat "--no-" check "-check"))
  10627 
  10628 (flycheck-define-checker puppet-lint
  10629   "A Puppet DSL style checker using puppet-lint.
  10630 
  10631 See URL `https://puppet-lint.com/'."
  10632   ;; We must check the original file, because Puppetlint is quite picky on the
  10633   ;; names of files and there place in the directory structure, to comply with
  10634   ;; Puppet's autoload directory layout.  For instance, a class foo::bar is
  10635   ;; required to be in a file foo/bar.pp.  Any other place, such as a Flycheck
  10636   ;; temporary file will cause an error.
  10637   :command ("puppet-lint"
  10638             (config-file "--config" flycheck-puppet-lint-rc)
  10639             "--log-format"
  10640             "%{path}:%{line}:%{kind}: %{message} (%{check})"
  10641             (option-list "" flycheck-puppet-lint-disabled-checks concat
  10642                          flycheck-puppet-lint-disabled-arg-name)
  10643             source-original)
  10644   :error-patterns
  10645   ((warning line-start (file-name) ":" line ":warning: " (message) line-end)
  10646    (error line-start (file-name) ":" line ":error: " (message) line-end))
  10647   :modes puppet-mode
  10648   ;; Since we check the original file, we can only use this syntax checker if
  10649   ;; the buffer is actually linked to a file, and if it is not modified.
  10650   :predicate flycheck-buffer-saved-p)
  10651 
  10652 (defun flycheck-python-run-snippet (checker snippet)
  10653   "Run a python SNIPPET and return the output.
  10654 
  10655 CHECKER's executable is assumed to be a Python REPL."
  10656   (when-let (output (flycheck-call-checker-process-for-output
  10657                      checker nil nil "-c" snippet))
  10658     (string-trim output)))
  10659 
  10660 (defun flycheck-python-get-path (checker)
  10661   "Compute the current Python path (CHECKER is a Python REPL) ."
  10662   (flycheck-python-run-snippet checker "import sys; print(sys.path[1:])"))
  10663 
  10664 (defun flycheck-python-find-module (checker module)
  10665   "Check if a Python MODULE is available (CHECKER is a Python REPL)."
  10666   (flycheck-python-run-snippet
  10667    checker (concat "import sys; sys.path.pop(0);"
  10668                    (format "import %s; print(%s.__file__)" module module))))
  10669 
  10670 (defun flycheck-python-needs-module-p (checker)
  10671   "Determine whether CHECKER needs to be invoked through Python.
  10672 
  10673 Previous versions of Flycheck called pylint and flake8 directly,
  10674 while new version call them through `python -c'.  This check
  10675 ensures that we don't break existing code; it also allows people
  10676 who use virtualenvs to run globally-installed checkers."
  10677   (not (string-match-p (rx (or "pylint" "pylint3" "flake8")
  10678                            (or "-script.pyw" ".exe" ".bat" "")
  10679                            eos)
  10680                        (flycheck-checker-executable checker))))
  10681 
  10682 (defun flycheck-python-verify-module (checker module)
  10683   "Verify that a Python MODULE is available.
  10684 
  10685 Return nil if CHECKER's executable is not a Python REPL.  This
  10686 function's is suitable for a checker's :verify."
  10687   (when (flycheck-python-needs-module-p checker)
  10688     (let ((mod-path (flycheck-python-find-module checker module)))
  10689       (list (flycheck-verification-result-new
  10690              :label (format "`%s' module" module)
  10691              :message (if mod-path (format "Found at %S" mod-path)
  10692                         (format "Missing; sys.path is %s"
  10693                                 (flycheck-python-get-path checker)))
  10694              :face (if mod-path 'success '(bold error)))))))
  10695 
  10696 (defun flycheck-python-module-args (checker module-name)
  10697   "Compute arguments to pass to CHECKER's executable to run MODULE-NAME.
  10698 
  10699 Return nil if CHECKER's executable is not a Python REPL.
  10700 Otherwise, return a list starting with -c (-m is not enough
  10701 because it adds the current directory to Python's path)."
  10702   (when (flycheck-python-needs-module-p checker)
  10703     `("-c" ,(concat "import sys;sys.path.pop(0);import runpy;"
  10704                     (format "runpy.run_module(%S, run_name='__main__')" module-name )))))
  10705 
  10706 (defcustom flycheck-python-project-files
  10707   '("pyproject.toml" "setup.cfg" "mypy.ini" "pyrightconfig.json")
  10708   "Files used to find where to run Python checkers from.
  10709 Currently used for pylint, flake8, and pyright.
  10710 
  10711 The presence of one in these files indicates the root of the
  10712 current project; `.pylintrc' is not part of the list because it
  10713 is commonly found in ~/."
  10714   :group 'flycheck
  10715   :type '(repeat (string :tag "File name"))
  10716   :package-version '(flycheck . "33")
  10717   :safe #'flycheck-string-list-p)
  10718 
  10719 (defun flycheck-python-find-project-root (_checker)
  10720   "Find the root directory of a Python project.
  10721 
  10722 The root directory is assumed to be the nearest parent directory
  10723 that contains one of `flycheck-python-project-files'.  If no such
  10724 file is found, we use the same heuristic as epylint: the nearest
  10725 parent directory that doesn't have a __init__.py file."
  10726   (let ((start (if buffer-file-name
  10727                    (file-name-directory buffer-file-name)
  10728                  default-directory)))
  10729     (or (flycheck--locate-dominating-file-matching
  10730          start (regexp-opt flycheck-python-project-files))
  10731         (locate-dominating-file
  10732          start (lambda (dir)
  10733                  (not (file-exists-p (expand-file-name "__init__.py" dir))))))))
  10734 
  10735 (flycheck-def-config-file-var flycheck-flake8rc python-flake8
  10736                               '(".flake8" "setup.cfg" "tox.ini"))
  10737 
  10738 (flycheck-def-option-var flycheck-flake8-error-level-alist
  10739     '(("^E9.*$"  . error)               ; Syntax errors from pep8
  10740       ("^F82.*$" . error)               ; undefined variables from pyflakes
  10741       ("^F83.*$" . error)               ; Duplicate arguments from flake8
  10742       ("^D.*$"   . info)                ; Docstring issues from flake8-pep257
  10743       ("^N.*$"   . info)                ; Naming issues from pep8-naming
  10744       )
  10745     python-flake8
  10746   "An alist mapping flake8 error IDs to Flycheck error levels.
  10747 
  10748 Each item in this list is a cons cell `(PATTERN . LEVEL)' where
  10749 PATTERN is a regular expression matched against the error ID, and
  10750 LEVEL is a Flycheck error level symbol.
  10751 
  10752 Each PATTERN is matched in the order of appearance in this list
  10753 against the error ID.  If it matches the ID, the level of the
  10754 corresponding error is set to LEVEL.  An error that is not
  10755 matched by any PATTERN defaults to warning level.
  10756 
  10757 The default value of this option matches errors from flake8
  10758 itself and from the following flake8 plugins:
  10759 
  10760 - pep8-naming
  10761 - flake8-pep257
  10762 
  10763 You may add your own mappings to this option in order to support
  10764 further flake8 plugins."
  10765   :type '(repeat (cons (regexp :tag "Error ID pattern")
  10766                        (symbol :tag "Error level")))
  10767   :package-version '(flycheck . "0.22"))
  10768 
  10769 (flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8
  10770   "The maximum McCabe complexity of methods.
  10771 
  10772 If nil, do not check the complexity of methods.  If set to an
  10773 integer, report any complexity greater than the value of this
  10774 variable as warning.
  10775 
  10776 If set to an integer, this variable overrules any similar setting
  10777 in the configuration file denoted by `flycheck-flake8rc'."
  10778   :type '(choice (const :tag "Do not check McCabe complexity" nil)
  10779                  (integer :tag "Maximum complexity"))
  10780   :safe #'integerp)
  10781 
  10782 (flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8
  10783   "The maximum length of lines.
  10784 
  10785 If set to an integer, the value of this variable denotes the
  10786 maximum length of lines, overruling any similar setting in the
  10787 configuration file denoted by `flycheck-flake8rc'.  An error will
  10788 be reported for any line longer than the value of this variable.
  10789 
  10790 If set to nil, use the maximum line length from the configuration
  10791 file denoted by `flycheck-flake8rc', or the PEP 8 recommendation
  10792 of 79 characters if there is no configuration with this setting."
  10793   :type '(choice (const :tag "Default value")
  10794                  (integer :tag "Maximum line length in characters"))
  10795   :safe #'integerp)
  10796 
  10797 (defun flycheck-flake8-fix-error-level (err)
  10798   "Fix the error level of ERR.
  10799 
  10800 Update the error level of ERR according to
  10801 `flycheck-flake8-error-level-alist'."
  10802   (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist)
  10803     (when (string-match-p pattern (flycheck-error-id err))
  10804       (setf (flycheck-error-level err) level)))
  10805   err)
  10806 
  10807 (defun flycheck-flake8--find-project-root (_checker)
  10808   "Find setup.cfg in a parent directory of the current buffer."
  10809   ;; This is a workaround for `https://gitlab.com/pycqa/flake8/issues/517'; see
  10810   ;; also `https://github.com/flycheck/flycheck/issues/1722'
  10811   (locate-dominating-file (or buffer-file-name default-directory) "setup.cfg"))
  10812 
  10813 (flycheck-define-checker python-flake8
  10814   "A Python syntax and style checker using Flake8.
  10815 
  10816 Requires Flake8 3.0 or newer. See URL
  10817 `https://flake8.readthedocs.io/'."
  10818   ;; Not calling flake8 directly makes it easier to switch between different
  10819   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
  10820   :command ("python3"
  10821             (eval (flycheck-python-module-args 'python-flake8 "flake8"))
  10822             "--format=default"
  10823             (config-file "--append-config" flycheck-flake8rc)
  10824             (option "--max-complexity" flycheck-flake8-maximum-complexity nil
  10825                     flycheck-option-int)
  10826             (option "--max-line-length" flycheck-flake8-maximum-line-length nil
  10827                     flycheck-option-int)
  10828             (eval (when buffer-file-name
  10829                     (concat "--stdin-display-name=" buffer-file-name)))
  10830             "-")
  10831   :standard-input t
  10832   :working-directory flycheck-python-find-project-root
  10833   :error-filter (lambda (errors)
  10834                   (let ((errors (flycheck-sanitize-errors errors)))
  10835                     (seq-map #'flycheck-flake8-fix-error-level errors)))
  10836   :error-patterns
  10837   ((warning line-start
  10838             (file-name) ":" line ":" (optional column ":") " "
  10839             (id (one-or-more (any alpha)) (one-or-more digit)) " "
  10840             (message (one-or-more not-newline))
  10841             line-end))
  10842   :enabled (lambda ()
  10843              (or (not (flycheck-python-needs-module-p 'python-flake8))
  10844                  (flycheck-python-find-module 'python-flake8 "flake8")))
  10845   :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8"))
  10846   :modes (python-mode python-ts-mode)
  10847   :next-checkers ((warning . python-pylint)
  10848                   (warning . python-mypy)))
  10849 
  10850 (flycheck-def-config-file-var flycheck-python-ruff-config python-ruff
  10851                               '("pyproject.toml" "ruff.toml" ".ruff.toml"))
  10852 
  10853 (flycheck-define-checker python-ruff
  10854   "A Python syntax and style checker using Ruff.
  10855 
  10856 See URL `https://docs.astral.sh/ruff/'."
  10857   :command ("ruff"
  10858             "check"
  10859             (config-file "--config" flycheck-python-ruff-config)
  10860             "--output-format=concise"
  10861             (option "--stdin-filename" buffer-file-name)
  10862             "-")
  10863   :standard-input t
  10864   :error-filter (lambda (errors)
  10865                   (let* ((errors (flycheck-sanitize-errors errors))
  10866                          (errors-with-ids (seq-filter #'flycheck-error-id errors)))
  10867                     (seq-union
  10868                      (seq-difference errors errors-with-ids)
  10869                      (seq-map #'flycheck-flake8-fix-error-level errors-with-ids))))
  10870   :error-patterns
  10871   ((error line-start
  10872           (or "-" (file-name)) ":" line ":" (optional column ":") " "
  10873           "SyntaxError: "
  10874           (message (one-or-more not-newline))
  10875           line-end)
  10876    (warning line-start
  10877             (or "-" (file-name)) ":" line ":" (optional column ":") " "
  10878             (id (one-or-more (any alpha)) (one-or-more digit) " ")
  10879             (message (one-or-more not-newline))
  10880             line-end))
  10881   :working-directory flycheck-python-find-project-root 
  10882   :modes (python-mode python-ts-mode)
  10883   :next-checkers ((warning . python-mypy)))
  10884 
  10885 (flycheck-def-config-file-var
  10886     flycheck-pylintrc python-pylint
  10887     '("pylintrc" ".pylintrc" "pyproject.toml" "setup.cfg"))
  10888 
  10889 (flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint
  10890   "Whether to use pylint message symbols or message codes.
  10891 
  10892 A pylint message has both an opaque identifying code (such as `F0401') and a
  10893 more meaningful symbolic code (such as `import-error').  This option governs
  10894 which should be used and reported to the user."
  10895   :type 'boolean
  10896   :safe #'booleanp
  10897   :package-version '(flycheck . "0.25"))
  10898 
  10899 (defun flycheck-parse-pylint (output checker buffer)
  10900   "Parse JSON OUTPUT of CHECKER on BUFFER as Pylint errors."
  10901   (mapcar (lambda (err)
  10902             (let-alist err
  10903               ;; Pylint can return -1 as a line or a column, hence the call to
  10904               ;; `max'.  See `https://github.com/flycheck/flycheck/issues/1383'.
  10905               (flycheck-error-new-at
  10906                (and .line (max .line 1))
  10907                (and .column (max (1+ .column) 1))
  10908                (pcase .type
  10909                  ;; See "pylint/utils.py"
  10910                  ((or "fatal" "error") 'error)
  10911                  ((or "info" "convention") 'info)
  10912                  ((or "warning" "refactor" _) 'warning))
  10913                ;; Drop lines showing the error in context
  10914                (and (string-match (rx (*? nonl) eol) .message)
  10915                     (match-string 0 .message))
  10916                :id (if flycheck-pylint-use-symbolic-id .symbol .message-id)
  10917                :checker checker
  10918                :buffer buffer
  10919                :filename .path)))
  10920           (car (flycheck-parse-json output))))
  10921 
  10922 (flycheck-define-checker python-pylint
  10923   "A Python syntax and style checker using Pylint.
  10924 
  10925 This syntax checker requires Pylint 1.0 or newer.
  10926 
  10927 See URL `https://www.pylint.org/'."
  10928   ;; --reports=n disables the scoring report.
  10929   ;; Not calling pylint directly makes it easier to switch between different
  10930   ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055.
  10931   :command ("python3"
  10932             (eval (flycheck-python-module-args 'python-pylint "pylint"))
  10933             "--reports=n"
  10934             "--output-format=json"
  10935             (config-file "--rcfile=" flycheck-pylintrc concat)
  10936             ;; Need `source-inplace' for relative imports (e.g. `from .foo
  10937             ;; import bar'), see https://github.com/flycheck/flycheck/issues/280
  10938             source-inplace)
  10939   :error-parser flycheck-parse-pylint
  10940   :working-directory flycheck-python-find-project-root
  10941   :enabled (lambda ()
  10942              (or (not (flycheck-python-needs-module-p 'python-pylint))
  10943                  (flycheck-python-find-module 'python-pylint "pylint")))
  10944   :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint"))
  10945   :error-explainer (lambda (err)
  10946                      (when-let (id (flycheck-error-id err))
  10947                        (apply
  10948                         #'flycheck-call-checker-process-for-output
  10949                         'python-pylint nil t
  10950                         (append
  10951                          (flycheck-python-module-args 'python-pylint "pylint")
  10952                          (list (format "--help-msg=%s" id))))))
  10953   :modes (python-mode python-ts-mode)
  10954   :next-checkers ((warning . python-mypy)))
  10955 
  10956 (flycheck-define-checker python-pycompile
  10957   "A Python syntax checker using Python's builtin compiler.
  10958 
  10959 See URL `https://docs.python.org/3.4/library/py_compile.html'."
  10960   :command ("python3" "-m" "py_compile" source)
  10961   :error-patterns
  10962   ;; Python 2.7
  10963   ((error line-start "  File \"" (file-name) "\", line " line "\n"
  10964           (>= 2 (zero-or-more not-newline) "\n")
  10965           "SyntaxError: " (message) line-end)
  10966    (error line-start "Sorry: IndentationError: "
  10967           (message) "(" (file-name) ", line " line ")"
  10968           line-end)
  10969    ;; 2.6
  10970    (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'"))))
  10971           "', ('" (file-name (one-or-more (not (any "'")))) "', "
  10972           line ", " column ", " (one-or-more not-newline) line-end))
  10973   :working-directory flycheck-python-find-project-root
  10974   :modes (python-mode python-ts-mode)
  10975   :next-checkers ((warning . python-mypy)))
  10976 
  10977 (defun flycheck-pyright--parse-error (output checker buffer)
  10978   "Parse pyright errors/warnings from JSON OUTPUT.
  10979 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  10980 the BUFFER that was checked respectively."
  10981   (seq-map
  10982    (lambda (err)
  10983      (let-alist err
  10984        (flycheck-error-new-at
  10985         (+ 1 .range.start.line)
  10986         (+ 1 .range.start.character)
  10987         (pcase .severity
  10988           ("error" 'error)
  10989           ("warning" 'warning)
  10990           (_ 'warning))
  10991         .message
  10992         :end-line (+ 1 .range.end.line)
  10993         :end-column (+ 1 .range.end.character)
  10994         :checker checker
  10995         :buffer buffer
  10996         :filename (buffer-file-name buffer))))
  10997    (cdr (nth 2 (car (flycheck-parse-json output))))))
  10998 
  10999 (flycheck-define-checker python-pyright
  11000   "Static type checker for Python
  11001 
  11002 See URL https://github.com/microsoft/pyright."
  11003   :command ("pyright"
  11004             "--outputjson"
  11005             source-inplace)
  11006   :working-directory flycheck-python-find-project-root
  11007   :error-parser flycheck-pyright--parse-error
  11008   :modes (python-mode python-ts-mode))
  11009 
  11010 (define-obsolete-variable-alias 'flycheck-python-mypy-ini
  11011   'flycheck-python-mypy-config "32")
  11012 
  11013 (flycheck-def-config-file-var flycheck-python-mypy-config python-mypy
  11014                               '("mypy.ini" "pyproject.toml" "setup.cfg"))
  11015 
  11016 (flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy
  11017   "Directory used to write .mypy_cache directories."
  11018   :type '(choice
  11019           (const :tag "Write to the working directory" nil)
  11020           (const :tag "Never write .mypy_cache directories" null-device)
  11021           (string :tag "Path"))
  11022   :safe #'flycheck-string-or-nil-p
  11023   :package-version '(flycheck . "32"))
  11024 
  11025 (flycheck-def-option-var flycheck-python-mypy-python-executable nil python-mypy
  11026   "Python executable to find the installed PEP 561 packages."
  11027   :type '(choice (const :tag "Same as mypy's" nil)
  11028                  (string :tag "Path"))
  11029   :safe #'flycheck-string-or-nil-p
  11030   :package-version '(flycheck . "33"))
  11031 
  11032 (flycheck-define-checker python-mypy
  11033   "Mypy syntax and type checker.  Requires mypy>=0.730.
  11034 
  11035 See URL `https://mypy-lang.org/'."
  11036   :command ("mypy"
  11037             "--show-column-numbers"
  11038             "--no-pretty"
  11039             (config-file "--config-file" flycheck-python-mypy-config)
  11040             (option "--cache-dir" flycheck-python-mypy-cache-dir)
  11041             (option "--python-executable" flycheck-python-mypy-python-executable)
  11042             source-original)
  11043   :error-patterns
  11044   ((error line-start (file-name) ":" line (optional ":" column)
  11045           ": error:" (message) line-end)
  11046    (warning line-start (file-name) ":" line (optional ":" column)
  11047             ": warning:" (message) line-end)
  11048    (info line-start (file-name) ":" line (optional ":" column)
  11049          ": note:" (message) line-end))
  11050   :working-directory flycheck-python-find-project-root
  11051   :modes (python-mode python-ts-mode)
  11052   ;; Ensure the file is saved, to work around
  11053   ;; https://github.com/python/mypy/issues/4746.
  11054   :predicate flycheck-buffer-saved-p)
  11055 
  11056 (flycheck-def-option-var flycheck-lintr-caching t r-lintr
  11057   "Whether to enable caching in lintr.
  11058 
  11059 By default, lintr caches all expressions in a file and re-checks
  11060 only those that have changed.  Setting this option to nil
  11061 disables caching in case there are problems."
  11062   :type 'boolean
  11063   :safe #'booleanp
  11064   :package-version '(flycheck . "0.23"))
  11065 
  11066 (flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr
  11067   "Linters to use with lintr.
  11068 
  11069 The value of this variable is a string containing an R
  11070 expression, which selects linters for lintr."
  11071   :type 'string
  11072   :risky t
  11073   :package-version '(flycheck . "0.23"))
  11074 
  11075 (defun flycheck-r-has-lintr (checker)
  11076   "Whether CHECKER (R) has installed the `lintr' library."
  11077   (eql 0 (flycheck-call-checker-process
  11078           checker nil nil nil
  11079           "--slave" "--no-restore" "--no-save" "-e"
  11080           "library('lintr')")))
  11081 
  11082 (flycheck-define-checker r-lintr
  11083   "An R style and syntax checker using the lintr package.
  11084 
  11085 See URL `https://github.com/jimhester/lintr'."
  11086   :command ("R" "--slave" "--no-restore" "--no-save" "-e"
  11087             (eval (concat
  11088                    "library(lintr);"
  11089                    "try(lint(commandArgs(TRUE)"
  11090                    ", cache=" (if flycheck-lintr-caching "TRUE" "FALSE")
  11091                    ", " flycheck-lintr-linters
  11092                    "))"))
  11093             "--args" source)
  11094   :error-patterns
  11095   ((info line-start (file-name) ":" line ":" column ": style: " (message)
  11096          line-end)
  11097    (warning line-start (file-name) ":" line ":" column ": warning: " (message)
  11098             line-end)
  11099    (error line-start (file-name) ":" line ":" column ": error: " (message)
  11100           line-end))
  11101   :modes (ess-mode ess-r-mode)
  11102   :predicate
  11103   ;; Don't check ESS files which do not contain R, and make sure that lintr is
  11104   ;; actually available
  11105   (lambda ()
  11106     (and (equal ess-language "S")
  11107          (flycheck-r-has-lintr 'r-lintr)))
  11108   :verify (lambda (checker)
  11109             (let ((has-lintr (flycheck-r-has-lintr checker)))
  11110               (list
  11111                (flycheck-verification-result-new
  11112                 :label "lintr library"
  11113                 :message (if has-lintr "present" "missing")
  11114                 :face (if has-lintr 'success '(bold error)))))))
  11115 
  11116 (flycheck-define-checker r
  11117   "An R syntax checker using the builtin `parse' function.
  11118 
  11119 See URL: `https://www.r-project.org/'."
  11120   :command ("R" "--slave" "--no-restore" "--no-save" "-e"
  11121             "parse(file=file('stdin'), srcfile='<stdin>')")
  11122   :standard-input t
  11123   :error-patterns
  11124   ((error line-start (zero-or-more space) "<stdin>:" line ":" column ": "
  11125           (message) line-end))
  11126   :modes (ess-mode ess-r-mode)
  11127   :predicate
  11128   ;; Don't check ESS files which do not contain R
  11129   (lambda () (equal ess-language "S")))
  11130 
  11131 (defun flycheck-racket-has-expand-p (checker)
  11132   "Whether the executable of CHECKER provides the `expand' command."
  11133   (eql 0 (flycheck-call-checker-process checker nil nil nil "expand")))
  11134 
  11135 (flycheck-define-checker racket
  11136   "A Racket syntax checker with `raco expand'.
  11137 
  11138 The `compiler-lib' racket package is required for this syntax
  11139 checker.
  11140 
  11141 See URL `https://racket-lang.org/'."
  11142   :command ("raco" "expand" source-inplace)
  11143   :predicate
  11144   (lambda ()
  11145     (and (or (not (eq major-mode 'scheme-mode))
  11146              ;; In `scheme-mode' we must check the current Scheme implementation
  11147              ;; being used
  11148              (and (boundp 'geiser-impl--implementation)
  11149                   (eq geiser-impl--implementation 'racket)))
  11150          (flycheck-racket-has-expand-p 'racket)))
  11151   :verify
  11152   (lambda (checker)
  11153     (let ((has-expand (flycheck-racket-has-expand-p checker))
  11154           (in-scheme-mode (eq major-mode 'scheme-mode))
  11155           (geiser-impl (bound-and-true-p geiser-impl--implementation)))
  11156       (list
  11157        (flycheck-verification-result-new
  11158         :label "compiler-lib package"
  11159         :message (if has-expand "present" "missing")
  11160         :face (if has-expand 'success '(bold error)))
  11161        (flycheck-verification-result-new
  11162         :label "Geiser Implementation"
  11163         :message (cond
  11164                   ((not in-scheme-mode) "Using Racket Mode")
  11165                   ((eq geiser-impl 'racket) "Racket")
  11166                   (geiser-impl (format "Other: %s" geiser-impl))
  11167                   (t "Geiser not active"))
  11168         :face (cond
  11169                ((or (not in-scheme-mode) (eq geiser-impl 'racket)) 'success)
  11170                (t '(bold error)))))))
  11171   :error-filter
  11172   (lambda (errors)
  11173     (flycheck-sanitize-errors
  11174      (flycheck-increment-error-columns
  11175       (seq-remove
  11176        (lambda (err)
  11177          (string-suffix-p
  11178           "/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt"
  11179           (flycheck-error-filename err)))
  11180        errors))))
  11181   :error-patterns
  11182   ((error line-start (zero-or-more space)
  11183           (file-name) ":" line ":" column ":" (message) line-end))
  11184   :modes (racket-mode scheme-mode))
  11185 
  11186 (flycheck-define-checker rpm-rpmlint
  11187   "A RPM SPEC file syntax checker using rpmlint.
  11188 
  11189 See URL `https://github.com/rpm-software-management/rpmlint'."
  11190   :command ("rpmlint" source)
  11191   :error-patterns
  11192   ((error line-start
  11193           (file-name) ":" (optional line ":") " E: " (message)
  11194           line-end)
  11195    (warning line-start
  11196             (file-name) ":" (optional line ":") " W: " (message)
  11197             line-end))
  11198   :error-filter
  11199   ;; rpmlint 1.1 outputs a spurious error for the temp file created by flycheck
  11200   (lambda (errors)
  11201     (dolist (err (seq-remove
  11202                   (lambda (err)
  11203                     (string-suffix-p "(none)" (flycheck-error-filename err)))
  11204                   errors))
  11205       ;; Add fake line numbers if they are missing in the lint output
  11206       (unless (flycheck-error-line err)
  11207         (setf (flycheck-error-line err) 1)))
  11208     errors)
  11209   :error-explainer
  11210   (lambda (error)
  11211     (when-let* ((error-message (flycheck-error-message error))
  11212                 (message-id (save-match-data
  11213                               (string-match "\\([^ ]+\\)" error-message)
  11214                               (match-string 1 error-message))))
  11215       (flycheck-call-checker-process-for-output
  11216        'rpm-rpmlint nil t "-I" message-id)))
  11217   :modes (sh-mode rpm-spec-mode)
  11218   :predicate (lambda () (or (not (eq major-mode 'sh-mode))
  11219                             ;; In `sh-mode', we need the proper shell
  11220                             (eq sh-shell 'rpm))))
  11221 
  11222 (flycheck-def-config-file-var flycheck-markdown-markdownlint-cli-config
  11223     markdown-markdownlint-cli
  11224     '(".markdownlint.json" ".markdownlint.jsonc" ".markdownlint.yaml")
  11225   :package-version '(flycheck . "33"))
  11226 
  11227 (flycheck-def-option-var flycheck-markdown-markdownlint-cli-disable-rules
  11228     nil markdown-markdownlint-cli
  11229   "Rules to disable for markdownlint-cli."
  11230   :type '(repeat :tag "Disabled rule"
  11231                  (string :tag "Rule name"))
  11232   :safe #'flycheck-string-list-p
  11233   :package-version '(flycheck . "33"))
  11234 
  11235 (flycheck-def-option-var flycheck-markdown-markdownlint-cli-enable-rules
  11236     nil markdown-markdownlint-cli
  11237   "Rules to enable for markdownlint-cli."
  11238   :type '(repeat :tag "Enabled rule"
  11239                  (string :tag "Rule name"))
  11240   :safe #'flycheck-string-list-p
  11241   :package-version '(flycheck . "33"))
  11242 
  11243 (flycheck-define-checker markdown-markdownlint-cli
  11244   "Markdown checker using markdownlint-cli.
  11245 
  11246 See URL `https://github.com/igorshubovych/markdownlint-cli'."
  11247   :command ("markdownlint"
  11248             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
  11249             (option-list "--disable" flycheck-markdown-markdownlint-cli-disable-rules)
  11250             (option-list "--enable" flycheck-markdown-markdownlint-cli-enable-rules)
  11251             "--"
  11252             source)
  11253   :error-patterns
  11254   ((error line-start
  11255           (file-name) ":" line
  11256           (? ":" column) " " (id (one-or-more (not (any space))))
  11257           " " (message) line-end))
  11258   :error-filter
  11259   (lambda (errors)
  11260     (flycheck-sanitize-errors
  11261      (flycheck-remove-error-file-names "(string)" errors)))
  11262   :modes (markdown-mode gfm-mode)
  11263   :error-explainer
  11264   (lambda (err)
  11265     (let ((error-code (substring (flycheck-error-id err) 0 5))
  11266           (url "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#%s"))
  11267       (and error-code `(url . ,(format url error-code))))))
  11268 
  11269 (flycheck-def-option-var flycheck-markdown-mdl-rules nil markdown-mdl
  11270   "Rules to enable for mdl.
  11271 
  11272 The value of this variable is a list of strings each of which is
  11273 the name of a rule to enable.
  11274 
  11275 By default all rules are enabled.
  11276 
  11277 See URL `https://git.io/vhi2t'."
  11278   :type '(repeat :tag "Enabled rules"
  11279                  (string :tag "rule name"))
  11280   :safe #'flycheck-string-list-p
  11281   :package-version '(flycheck . "27"))
  11282 
  11283 (flycheck-def-option-var flycheck-markdown-mdl-tags nil markdown-mdl
  11284   "Rule tags to enable for mdl.
  11285 
  11286 The value of this variable is a list of strings each of which is
  11287 the name of a rule tag.  Only rules with these tags are enabled.
  11288 
  11289 By default all rules are enabled.
  11290 
  11291 See URL `https://git.io/vhi2t'."
  11292   :type '(repeat :tag "Enabled tags"
  11293                  (string :tag "tag name"))
  11294   :safe #'flycheck-string-list-p
  11295   :package-version '(flycheck . "27"))
  11296 
  11297 (flycheck-def-config-file-var flycheck-markdown-mdl-style markdown-mdl nil
  11298   :package-version '(flycheck . "27"))
  11299 
  11300 (flycheck-define-checker markdown-mdl
  11301   "Markdown checker using mdl.
  11302 
  11303 See URL `https://github.com/markdownlint/markdownlint'."
  11304   :command ("mdl"
  11305             (config-file "--style" flycheck-markdown-mdl-style)
  11306             (option "--tags=" flycheck-markdown-mdl-tags concat
  11307                     flycheck-option-comma-separated-list)
  11308             (option "--rules=" flycheck-markdown-mdl-rules concat
  11309                     flycheck-option-comma-separated-list))
  11310   :standard-input t
  11311   :error-patterns
  11312   ((error line-start
  11313           (file-name) ":" line ": " (id (one-or-more alnum)) " " (message)
  11314           line-end))
  11315   :error-filter
  11316   (lambda (errors)
  11317     (flycheck-sanitize-errors
  11318      (flycheck-remove-error-file-names "(stdin)" errors)))
  11319   :modes (markdown-mode gfm-mode))
  11320 
  11321 (flycheck-def-config-file-var flycheck-markdown-pymarkdown-config
  11322     markdown-pymarkdown nil
  11323   :package-version '(flycheck . "34"))
  11324 
  11325 (flycheck-define-checker markdown-pymarkdown
  11326   "Markdown checker using PyMarkdown.
  11327 
  11328 See URL `https://pypi.org/project/pymarkdownlnt/'."
  11329   :command ("pymarkdown"
  11330             (config-file "--config" flycheck-markdown-markdownlint-cli-config)
  11331             "scan"
  11332             source)
  11333   :error-patterns
  11334   ((error line-start
  11335           (file-name) ":" line
  11336           (? ":" column) ": " (id (one-or-more alnum))
  11337           ": " (message) line-end))
  11338   :error-filter
  11339   (lambda (errors)
  11340     (flycheck-sanitize-errors
  11341      (flycheck-remove-error-file-names "(string)" errors)))
  11342   :modes (markdown-mode gfm-mode))
  11343 
  11344 (flycheck-define-checker nix
  11345   "Nix checker using nix-instantiate.
  11346 
  11347 See URL `https://nixos.org/nix/manual/#sec-nix-instantiate'."
  11348   :command ("nix-instantiate" "--parse" "-")
  11349   :standard-input t
  11350   :error-patterns
  11351   ((error line-start
  11352           "error: " (message)
  11353           (one-or-more "\n")
  11354           (zero-or-more space) "at «stdin»:" line ":" column ":" line-end)
  11355    (error line-start
  11356           "at: (" line ":" column ") from stdin"
  11357           (one-or-more "\n" (zero-or-more space (one-or-more not-newline)))
  11358           (message) line-end)
  11359    (error line-start
  11360           "error: " (message) " at " (file-name) ":" line ":" column
  11361           line-end))
  11362   :error-filter
  11363   (lambda (errors)
  11364     (flycheck-sanitize-errors
  11365      (flycheck-remove-error-file-names "(string)" errors)))
  11366   :next-checkers ((warning . nix-linter))
  11367   :modes (nix-mode nix-ts-mode))
  11368 
  11369 (defun flycheck-parse-nix-linter (output checker buffer)
  11370   "Parse nix-linter warnings from JSON OUTPUT.
  11371 
  11372 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  11373 the BUFFER that was checked respectively.
  11374 
  11375 See URL `https://github.com/Synthetica9/nix-linter' for more
  11376 information about nix-linter."
  11377   (mapcar (lambda (err)
  11378             (let-alist err
  11379               (flycheck-error-new-at
  11380                .pos.spanBegin.sourceLine
  11381                .pos.spanBegin.sourceColumn
  11382                'warning
  11383                .description
  11384                :id .offense
  11385                :checker checker
  11386                :buffer buffer
  11387                :filename (buffer-file-name buffer)
  11388                :end-line .pos.spanEnd.sourceLine
  11389                :end-column .pos.spanEnd.sourceColumn)))
  11390           (flycheck-parse-json output)))
  11391 
  11392 (flycheck-define-checker nix-linter
  11393   "Nix checker using nix-linter.
  11394 
  11395 See URL `https://github.com/Synthetica9/nix-linter'."
  11396   :command ("nix-linter" "--json-stream" "-")
  11397   :standard-input t
  11398   :error-parser flycheck-parse-nix-linter
  11399   :error-explainer
  11400   (lambda (error)
  11401     (when-let (error-code (flycheck-error-id error))
  11402       (flycheck-call-checker-process-for-output
  11403        'nix-linter nil t "--help-for" error-code)))
  11404   :modes (nix-mode nix-ts-mode))
  11405 
  11406 (defun flycheck-parse-statix (output checker buffer)
  11407   "Parse statix warnings from JSON OUTPUT.
  11408 
  11409 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  11410 the BUFFER that was checked respectively.
  11411 
  11412 See URL `https://github.com/nerdypepper/statix' for more
  11413 information about statix."
  11414   (mapcar (lambda (err)
  11415             ;; Diagnostic information is a (seemingly always) 1 element array.
  11416             (let-alist (car (alist-get 'diagnostics err))
  11417               (let ((message .message)
  11418                     (start-line .at.from.line)
  11419                     (start-column .at.from.column)
  11420                     (end-line .at.to.line)
  11421                     (end-column .at.to.column))
  11422 
  11423                 (let-alist err
  11424                   (flycheck-error-new-at
  11425                    start-line
  11426                    start-column
  11427                    (pcase .severity ("Error" 'error)
  11428                           ("Warn" 'warning)
  11429                           (_ 'warning))
  11430                    (format "%s: %s" .note message)
  11431                    :id (format "%s%02d" (pcase .severity
  11432                                           ("Error" "E")
  11433                                           ("Warn" "W")
  11434                                           (_ "")) .code)
  11435                    :checker checker
  11436                    :buffer buffer
  11437                    :filename (buffer-file-name buffer)
  11438                    :end-line end-line
  11439                    :end-column end-column)))))
  11440           (alist-get 'report (car (flycheck-parse-json output)))))
  11441 
  11442 (flycheck-define-checker statix
  11443   "Nix checker using statix.
  11444 
  11445 See URL `https://github.com/nerdypepper/statix'."
  11446   :command ("statix" "check" "-o=json" source)
  11447   :error-parser flycheck-parse-statix
  11448   :modes nix-mode)
  11449 
  11450 (defun flycheck-locate-sphinx-source-directory ()
  11451   "Locate the Sphinx source directory for the current buffer.
  11452 
  11453 Return the source directory, or nil, if the current buffer is not
  11454 part of a Sphinx project."
  11455   (when-let* ((filename (buffer-file-name))
  11456               (dir (locate-dominating-file filename "conf.py")))
  11457     (expand-file-name dir)))
  11458 
  11459 (flycheck-define-checker rst
  11460   "A ReStructuredText (RST) syntax checker using Docutils.
  11461 
  11462 See URL `https://docutils.sourceforge.net/'."
  11463   ;; include:: directives
  11464   :command ("rst2pseudoxml.py" "--report=2" "--halt=5"
  11465             ;; Read from standard input and throw output away
  11466             "-" null-device)
  11467   :standard-input t
  11468   :error-patterns
  11469   ((warning line-start "<stdin>:" line ": (WARNING/2) " (message) line-end)
  11470    (error line-start "<stdin>:" line
  11471           ": (" (or "ERROR/3" "SEVERE/4") ") "
  11472           (message) line-end))
  11473   :modes rst-mode)
  11474 
  11475 (flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx
  11476   "Whether to warn about missing references in Sphinx.
  11477 
  11478 When non-nil (the default), warn about all missing references in
  11479 Sphinx via `-n'."
  11480   :type 'boolean
  11481   :safe #'booleanp
  11482   :package-version '(flycheck . "0.17"))
  11483 
  11484 (flycheck-define-checker rst-sphinx
  11485   "A ReStructuredText (RST) syntax checker using Sphinx.
  11486 
  11487 Requires Sphinx 1.2 or newer.  See URL `https://sphinx-doc.org'."
  11488   :command ("sphinx-build" "-b" "pseudoxml"
  11489             "-q" "-N"                   ; Reduced output and no colors
  11490             (option-flag "-n" flycheck-sphinx-warn-on-missing-references)
  11491             (eval (flycheck-locate-sphinx-source-directory))
  11492             temporary-directory         ; Redirect the output to a temporary
  11493                                         ; directory
  11494             source-original)            ; Sphinx needs the original document
  11495   :error-patterns
  11496   ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end)
  11497    (error line-start
  11498           (file-name) ":" line
  11499           ": " (or "ERROR" "SEVERE") ": "
  11500           (message) line-end))
  11501   :modes rst-mode
  11502   :predicate (lambda () (and (flycheck-buffer-saved-p)
  11503                              (flycheck-locate-sphinx-source-directory))))
  11504 
  11505 (defun flycheck-ruby--find-project-root (_checker)
  11506   "Compute an appropriate working-directory for flycheck-ruby.
  11507 
  11508 This is either a parent directory containing a Gemfile, or nil."
  11509   (and
  11510    buffer-file-name
  11511    (locate-dominating-file buffer-file-name "Gemfile")))
  11512 
  11513 (defun flycheck-ruby--filter-rubocop-errors (errors)
  11514   "Filter RuboCop ERRORS attributed to dummy stdin filename."
  11515   (flycheck-remove-error-file-names
  11516    (flycheck--file-truename (expand-file-name "stdin"))
  11517    errors))
  11518 
  11519 (flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml")
  11520 
  11521 (flycheck-def-option-var flycheck-rubocop-lint-only nil
  11522                          (ruby-rubocop ruby-standard ruby-chef-cookstyle)
  11523   "Whether to only report code issues in Rubocop, Cookstyle and Standard.
  11524 
  11525 When non-nil, only report code issues, via `--lint'.  Otherwise
  11526 report style issues as well."
  11527   :safe #'booleanp
  11528   :type 'boolean
  11529   :package-version '(flycheck . "0.16"))
  11530 
  11531 (defconst flycheck-ruby-rubocop-error-patterns
  11532   '((info line-start (file-name) ":" line ":" column ": C: "
  11533           (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end)
  11534     (warning line-start (file-name) ":" line ":" column ": W: "
  11535              (optional (id (one-or-more (not (any ":")))) ": ") (message)
  11536              line-end)
  11537     (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": "
  11538            (optional (id (one-or-more (not (any ":")))) ": ") (message)
  11539            line-end)))
  11540 
  11541 (flycheck-def-executable-var ruby-rubocop "rubocop")
  11542 (flycheck-define-command-checker 'ruby-rubocop
  11543   "A Ruby syntax and style checker using the RuboCop tool.
  11544 
  11545 You need at least RuboCop 0.34 for this syntax checker.
  11546 
  11547 See URL `https://rubocop.org/'."
  11548   ;; ruby-standard is defined based on this checker
  11549   :command '("rubocop"
  11550              "--display-cop-names"
  11551              "--force-exclusion"
  11552              "--format" "emacs"
  11553              (config-file "--config" flycheck-rubocoprc)
  11554              (option-flag "--lint" flycheck-rubocop-lint-only)
  11555              ;; RuboCop takes the original file name as argument when reading
  11556              ;; from standard input, but it chokes when that name is the empty
  11557              ;; string, so fall back to "stdin" in order to handle buffers with
  11558              ;; no backing file (e.g. org-mode snippet buffers)
  11559              "--stdin" (eval (or (buffer-file-name) "stdin")))
  11560   :standard-input t
  11561   :working-directory #'flycheck-ruby--find-project-root
  11562   :error-patterns flycheck-ruby-rubocop-error-patterns
  11563   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11564   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11565   :next-checkers '((warning . ruby-reek)
  11566                    (warning . ruby-chef-cookstyle)))
  11567 
  11568 (flycheck-def-executable-var ruby-chef-cookstyle "cookstyle")
  11569 (flycheck-define-command-checker 'ruby-chef-cookstyle
  11570   "A Chef (Ruby) syntax and style checker using the Cookstyle tool.
  11571 Basically Cookstyle is a thin wrapper around RuboCop, so this
  11572 checker is essentially the same.
  11573 
  11574 See URL `https://github.com/chef/cookstyle'."
  11575   :command '("cookstyle"
  11576              "--display-cop-names"
  11577              "--force-exclusion"
  11578              "--format" "emacs"
  11579              (config-file "--config" flycheck-rubocoprc)
  11580              (option-flag "--lint" flycheck-rubocop-lint-only)
  11581              ;; RuboCop takes the original file name as argument when reading
  11582              ;; from standard input, but it chokes when that name is the empty
  11583              ;; string, so fall back to "stdin" in order to handle buffers with
  11584              ;; no backing file (e.g. org-mode snippet buffers)
  11585              "--stdin" (eval (or (buffer-file-name) "stdin")))
  11586   :standard-input t
  11587   :working-directory #'flycheck-ruby--find-project-root
  11588   :error-patterns flycheck-ruby-rubocop-error-patterns
  11589   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11590   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11591   :predicate
  11592   (lambda ()
  11593     (let ((parent-dir (file-name-directory
  11594                        (directory-file-name
  11595                         (expand-file-name default-directory)))))
  11596       (or
  11597        ;; Chef CookBook
  11598        ;; https://docs.opscode.com/chef/knife.html#id38
  11599        (locate-dominating-file parent-dir "recipes")
  11600        ;; Knife Solo
  11601        ;; https://matschaffer.github.io/knife-solo/#label-Init+command
  11602        (locate-dominating-file parent-dir "cookbooks"))))
  11603   :next-checkers '((warning . ruby-reek)))
  11604 
  11605 (flycheck-def-config-file-var flycheck-ruby-standardrc ruby-standard
  11606                               ".standard.yml")
  11607 
  11608 (flycheck-def-executable-var ruby-standard "standardrb")
  11609 (flycheck-define-command-checker 'ruby-standard
  11610   "A Ruby syntax and style checker using the StandardRB gem.
  11611 
  11612 See URL `https://github.com/testdouble/standard' for more information."
  11613   ;; This checker is derived from ruby-rubocop; see above
  11614   :command '("standardrb"
  11615              "--display-cop-names"
  11616              "--force-exclusion"
  11617              "--format" "emacs"
  11618              "--cache" "false"
  11619              (config-file "--config" flycheck-ruby-standardrc)
  11620              (option-flag "--lint" flycheck-rubocop-lint-only)
  11621              "--stdin" source-original)
  11622   :standard-input t
  11623   :working-directory #'flycheck-ruby--find-project-root
  11624   :error-patterns flycheck-ruby-rubocop-error-patterns
  11625   :error-filter #'flycheck-ruby--filter-rubocop-errors
  11626   :modes '(enh-ruby-mode ruby-mode ruby-ts-mode)
  11627   :next-checkers '((warning . ruby-reek)
  11628                    (warning . ruby-chef-cookstyle)))
  11629 
  11630 (flycheck-def-config-file-var flycheck-reekrc ruby-reek ".reek.yml"
  11631   :safe #'string-or-null-p
  11632   :package-version '(flycheck . "30"))
  11633 
  11634 (flycheck-define-checker ruby-reek
  11635   "A Ruby smell checker using reek.
  11636 
  11637 See URL `https://github.com/troessner/reek'."
  11638   :command ("reek" "--format" "json"
  11639             (config-file "--config" flycheck-reekrc)
  11640             source)
  11641   :error-parser flycheck-parse-reek
  11642   :modes (enh-ruby-mode ruby-mode ruby-ts-mode))
  11643 
  11644 (flycheck-define-checker ruby
  11645   "A Ruby syntax checker using the standard Ruby interpreter.
  11646 
  11647 Please note that the output of different Ruby versions and
  11648 implementations varies wildly.  This syntax checker supports
  11649 current versions of MRI and JRuby, but may break when used with
  11650 other implementations or future versions of these
  11651 implementations.
  11652 
  11653 Please consider using `ruby-rubocop' or `ruby-reek' instead.
  11654 
  11655 See URL `https://www.ruby-lang.org/'."
  11656   :command ("ruby" "-w" "-c")
  11657   :standard-input t
  11658   :error-patterns
  11659   ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv
  11660   ((error line-start "SyntaxError in -:" line ": " (message) line-end)
  11661    (warning line-start "-:" line ":" (optional column ":")
  11662             " warning: " (message) line-end)
  11663    (error line-start "-:" line ": " (message) line-end))
  11664   :modes (enh-ruby-mode ruby-mode ruby-ts-mode)
  11665   :next-checkers ((warning . ruby-chef-cookstyle)))
  11666 
  11667 (flycheck-define-checker ruby-jruby
  11668   "A Ruby syntax checker using the JRuby interpreter.
  11669 
  11670 This syntax checker is very primitive, and may break on future
  11671 versions of JRuby.
  11672 
  11673 Please consider using `ruby-rubocop' instead.
  11674 
  11675 See URL `https://jruby.org/'."
  11676   :command ("jruby" "-w" "-c")
  11677   :standard-input t
  11678   :error-patterns
  11679   ((error   line-start "SyntaxError in -:" line ": " (message) line-end)
  11680    (warning line-start "-:" line ": warning: " (message) line-end)
  11681    (error   line-start "-:" line ": "          (message) line-end))
  11682   :modes (enh-ruby-mode ruby-mode ruby-ts-mode))
  11683 
  11684 (flycheck-def-args-var flycheck-cargo-check-args (rust-cargo)
  11685   :package-version '(flycheck . "32"))
  11686 
  11687 (flycheck-def-args-var flycheck-rust-args (rust)
  11688   :package-version '(flycheck . "0.24"))
  11689 
  11690 (flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust)
  11691   "Whether to check test code in Rust.
  11692 
  11693 For the `rust' checker: When non-nil, `rustc' is passed the
  11694 `--test' flag, which will check any code marked with the
  11695 `#[cfg(test)]' attribute and any functions marked with
  11696 `#[test]'. Otherwise, `rustc' is not passed `--test' and test
  11697 code will not be checked.  Skipping `--test' is necessary when
  11698 using `#![no_std]', because compiling the test runner requires
  11699 `std'.
  11700 
  11701 For the `rust-cargo' checker: When non-nil, calls `cargo test
  11702 --no-run' instead of `cargo check'."
  11703   :type 'boolean
  11704   :safe #'booleanp
  11705   :package-version '("flycheck" . "0.19"))
  11706 
  11707 (flycheck-def-option-var flycheck-rust-crate-root nil rust
  11708   "A path to the crate root for the current buffer.
  11709 
  11710 The value of this variable is either a string with the path to
  11711 the crate root for the current buffer, or nil if the current buffer
  11712 is a crate.  A relative path is relative to the current buffer.
  11713 
  11714 If this variable is non nil the current buffer will only be checked
  11715 if it is not modified, i.e. after it has been saved."
  11716   :type '(choice (const :tag "Unspecified" nil)
  11717                  (file :tag "Root"))
  11718   :safe #'flycheck-string-or-nil-p
  11719   :package-version '(flycheck . "0.20"))
  11720 (make-variable-buffer-local 'flycheck-rust-crate-root)
  11721 
  11722 (flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust)
  11723   "The type of the Rust Crate to check.
  11724 
  11725 For `rust-cargo', the value should be a string denoting the
  11726 target type passed to Cargo.  See
  11727 `flycheck-rust-valid-crate-type-p' for the list of allowed
  11728 values.
  11729 
  11730 For `rust', the value should be a string denoting the crate type
  11731 for the `--crate-type' flag of rustc."
  11732   :type '(choice (const :tag "nil (rust/rust-cargo)" nil)
  11733                  (const :tag "lib (rust/rust-cargo)" "lib")
  11734                  (const :tag "bin (rust/rust-cargo)" "bin")
  11735                  (const :tag "example (rust-cargo)" "example")
  11736                  (const :tag "test (rust-cargo)" "test")
  11737                  (const :tag "bench (rust-cargo)" "bench")
  11738                  (const :tag "rlib (rust)" "rlib")
  11739                  (const :tag "dylib (rust)" "dylib")
  11740                  (const :tag "cdylib (rust)" "cdylib")
  11741                  (const :tag "staticlib (rust)" "staticlib")
  11742                  (const :tag "metadata (rust)" "metadata"))
  11743   :safe #'stringp
  11744   :package-version '(flycheck . "0.20"))
  11745 (make-variable-buffer-local 'flycheck-rust-crate-type)
  11746 
  11747 (flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo
  11748   "The name of the binary to pass to `cargo check --CRATE-TYPE'.
  11749 
  11750 The value of this variable is a string denoting the name of the
  11751 target to check: usually the name of the crate, or the name of
  11752 one of the files under `src/bin', `tests', `examples' or
  11753 `benches'.
  11754 
  11755 This always requires a non-nil value, unless
  11756 `flycheck-rust-crate-type' is `lib' or nil, in which case it is
  11757 ignored."
  11758   :type '(choice (const :tag "Unspecified" nil)
  11759                  (string :tag "Binary name"))
  11760   :safe #'flycheck-string-or-nil-p
  11761   :package-version '(flycheck . "28"))
  11762 (make-variable-buffer-local 'flycheck-rust-binary-name)
  11763 
  11764 (flycheck-def-option-var flycheck-rust-features nil rust-cargo
  11765   "List of features to activate during build or check.
  11766 
  11767 The value of this variable is a list of strings denoting features
  11768 that will be activated to build the target to check. Features will
  11769 be passed to `cargo check --features=FEATURES'."
  11770   :type '(repeat :tag "Features to activate"
  11771                  (string :tag "Feature"))
  11772   :safe #'flycheck-string-list-p
  11773   :package-version '(flycheck . "32"))
  11774 (make-variable-buffer-local 'flycheck-rust-features)
  11775 
  11776 (flycheck-def-option-var flycheck-rust-library-path nil rust
  11777   "A list of library directories for Rust.
  11778 
  11779 The value of this variable is a list of strings, where each
  11780 string is a directory to add to the library path of Rust.
  11781 Relative paths are relative to the file being checked."
  11782   :type '(repeat (directory :tag "Library directory"))
  11783   :safe #'flycheck-string-list-p
  11784   :package-version '(flycheck . "0.18"))
  11785 
  11786 (defun flycheck--fontify-as-markdown ()
  11787   "Place current buffer in `markdown-view-mode' and fontify it."
  11788   (when (fboundp 'markdown-view-mode)
  11789     (let ((markdown-fontify-code-block-default-mode 'rust-mode)
  11790           (markdown-fontify-code-blocks-natively t)
  11791           (markdown-hide-markup t))
  11792       (markdown-view-mode)
  11793       (font-lock-flush)
  11794       (font-lock-ensure))))
  11795 
  11796 (defun flycheck-rust-error-explainer (error)
  11797   "Return an explanation for the given `flycheck-error' ERROR."
  11798   (when-let (error-code (flycheck-error-id error))
  11799     (lambda ()
  11800       (flycheck-call-checker-process
  11801        'rust nil standard-output t "--explain" error-code)
  11802       (with-current-buffer standard-output
  11803         (flycheck--fontify-as-markdown)))))
  11804 
  11805 (defun flycheck-rust-error-filter (errors)
  11806   "Filter ERRORS from rustc output that have no explanatory value."
  11807   (seq-remove
  11808    (lambda (err)
  11809      (or
  11810       ;; Macro errors emit a diagnostic in a phony file,
  11811       ;; e.g. "<println macros>".
  11812       (when-let (filename (flycheck-error-filename err))
  11813         (string-match-p (rx "macros>" line-end) filename))
  11814       ;; Redundant message giving the number of failed errors
  11815       (when-let (msg (flycheck-error-message err))
  11816         (string-match-p
  11817          (rx
  11818           (or (: "aborting due to " (optional (one-or-more num) " ")
  11819                  "previous error")
  11820               (: "For more information about this error, try `rustc --explain "
  11821                  (one-or-more alnum) "`.")))
  11822          msg))))
  11823    errors))
  11824 
  11825 (defun flycheck-rust-manifest-directory ()
  11826   "Return the nearest directory holding the Cargo manifest.
  11827 
  11828 Return the nearest directory containing the `Cargo.toml' manifest
  11829 file, starting from the current buffer and using
  11830 `locate-dominating-file'.  Return nil if there is no such file,
  11831 or if the current buffer has no file name."
  11832   (and buffer-file-name
  11833        (locate-dominating-file buffer-file-name "Cargo.toml")))
  11834 
  11835 (defun flycheck-rust-cargo-metadata ()
  11836   "Run `cargo metadata' and return the result as parsed JSON object."
  11837   (car (flycheck-parse-json
  11838         (flycheck-call-checker-process-for-output
  11839          'rust-cargo nil t
  11840          "metadata" "--no-deps" "--format-version" "1"))))
  11841 
  11842 (defun flycheck-rust-cargo-workspace-root ()
  11843   "Return the path to the workspace root of a Rust Cargo project.
  11844 
  11845 Return nil if the workspace root does not exist (for Rust
  11846 versions inferior to 1.25)."
  11847   (let-alist (flycheck-rust-cargo-metadata)
  11848     .workspace_root))
  11849 
  11850 (defun flycheck-rust-cargo-has-command-p (command)
  11851   "Whether Cargo has COMMAND in its list of commands.
  11852 
  11853 Execute `cargo --list' to find out whether COMMAND is present."
  11854   (let ((cargo (funcall flycheck-executable-find "cargo")))
  11855     (member command
  11856             (mapcar (lambda (line)
  11857                       (replace-regexp-in-string "\\s-*\\(\\S-+\\).*\\'" "\\1" line))
  11858                     (ignore-errors (process-lines cargo "--list"))))))
  11859 
  11860 (defun flycheck-rust-valid-crate-type-p (crate-type)
  11861   "Whether CRATE-TYPE is a valid target type for Cargo.
  11862 
  11863 A valid Cargo target type is one of `lib', `bin', `example',
  11864 `test' or `bench'."
  11865   (member crate-type '(nil "lib" "bin" "example" "test" "bench")))
  11866 
  11867 (flycheck-define-checker rust-cargo
  11868   "A Rust syntax checker using Cargo.
  11869 
  11870 This syntax checker requires Rust 1.17 or newer.  See URL
  11871 `https://www.rust-lang.org'."
  11872   :command ("cargo"
  11873             (eval (if flycheck-rust-check-tests
  11874                       "test"
  11875                     "check"))
  11876             (eval (when flycheck-rust-check-tests
  11877                     "--no-run"))
  11878             (eval (when flycheck-rust-crate-type
  11879                     (concat "--" flycheck-rust-crate-type)))
  11880             ;; All crate targets except "lib" need a binary name
  11881             (eval (when (and flycheck-rust-crate-type
  11882                              (not (string= flycheck-rust-crate-type "lib")))
  11883                     flycheck-rust-binary-name))
  11884             (option "--features=" flycheck-rust-features concat
  11885                     flycheck-option-comma-separated-list)
  11886             (eval flycheck-cargo-check-args)
  11887             "--message-format=json")
  11888   :error-parser flycheck-parse-cargo-rustc
  11889   :error-filter (lambda (errors)
  11890                   ;; In Rust 1.25+, filenames are relative to the workspace
  11891                   ;; root.
  11892                   (let ((root (flycheck-rust-cargo-workspace-root)))
  11893                     (seq-do (lambda (err)
  11894                               ;; Some errors are crate level and do not have a
  11895                               ;; filename
  11896                               (when (flycheck-error-filename err)
  11897                                 (setf (flycheck-error-filename err)
  11898                                       (expand-file-name
  11899                                        (flycheck-error-filename err) root))))
  11900                             (flycheck-rust-error-filter errors))))
  11901   :error-explainer flycheck-rust-error-explainer
  11902   :modes (rust-mode rust-ts-mode)
  11903   :predicate flycheck-buffer-saved-p
  11904   :enabled flycheck-rust-manifest-directory
  11905   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
  11906   :verify
  11907   (lambda (_)
  11908     (and buffer-file-name
  11909          (let* ((has-toml (flycheck-rust-manifest-directory))
  11910                 (valid-crate-type (flycheck-rust-valid-crate-type-p
  11911                                    flycheck-rust-crate-type))
  11912                 (need-binary-name
  11913                  (and flycheck-rust-crate-type
  11914                       (not (string= flycheck-rust-crate-type "lib")))))
  11915            (list
  11916             (flycheck-verification-result-new
  11917              :label "Cargo.toml"
  11918              :message (if has-toml "Found" "Missing")
  11919              :face (if has-toml 'success '(bold warning)))
  11920             (flycheck-verification-result-new
  11921              :label "Crate type"
  11922              :message (if valid-crate-type
  11923                           (format "%s" flycheck-rust-crate-type)
  11924                         (format "%s (invalid, should be one of 'lib', 'bin', \
  11925 'test', 'example' or 'bench')"
  11926                                 flycheck-rust-crate-type))
  11927              :face (if valid-crate-type 'success '(bold error)))
  11928             (flycheck-verification-result-new
  11929              :label "Binary name"
  11930              :message (cond
  11931                        ((not need-binary-name) "Not required")
  11932                        ((not flycheck-rust-binary-name) "Required")
  11933                        (t (format "%s" flycheck-rust-binary-name)))
  11934              :face (cond
  11935                     ((not need-binary-name) 'success)
  11936                     ((not flycheck-rust-binary-name) '(bold error))
  11937                     (t 'success))))))))
  11938 
  11939 (flycheck-define-checker rust
  11940   "A Rust syntax checker using Rust compiler.
  11941 
  11942 This syntax checker needs Rust 1.18 or newer.  See URL
  11943 `https://www.rust-lang.org'."
  11944   :command ("rustc"
  11945             (option "--crate-type" flycheck-rust-crate-type)
  11946             "--emit=mir" "-o" "/dev/null" ; avoid creating binaries
  11947             "--error-format=json"
  11948             (option-flag "--test" flycheck-rust-check-tests)
  11949             (option-list "-L" flycheck-rust-library-path concat)
  11950             (eval flycheck-rust-args)
  11951             (eval (or flycheck-rust-crate-root
  11952                       (flycheck-substitute-argument 'source-original 'rust))))
  11953   :error-parser flycheck-parse-rustc
  11954   :error-filter flycheck-rust-error-filter
  11955   :error-explainer flycheck-rust-error-explainer
  11956   :modes (rust-mode rust-ts-mode)
  11957   :predicate flycheck-buffer-saved-p)
  11958 
  11959 (flycheck-define-checker rust-clippy
  11960   "A Rust syntax checker using clippy.
  11961 
  11962 See URL `https://github.com/rust-lang-nursery/rust-clippy'."
  11963   :command ("cargo" "clippy" "--message-format=json")
  11964   :error-parser flycheck-parse-cargo-rustc
  11965   :error-filter flycheck-rust-error-filter
  11966   :error-explainer flycheck-rust-error-explainer
  11967   :modes (rust-mode rust-ts-mode)
  11968   :predicate flycheck-buffer-saved-p
  11969   :enabled (lambda ()
  11970              (and (flycheck-rust-cargo-has-command-p "clippy")
  11971                   (flycheck-rust-manifest-directory)))
  11972   :working-directory (lambda (_) (flycheck-rust-manifest-directory))
  11973   :verify
  11974   (lambda (_)
  11975     (and buffer-file-name
  11976          (let ((has-toml (flycheck-rust-manifest-directory))
  11977                (has-clippy (flycheck-rust-cargo-has-command-p "clippy")))
  11978            (list
  11979             (flycheck-verification-result-new
  11980              :label "Clippy"
  11981              :message (if has-clippy "Found"
  11982                         "Cannot find the `cargo clippy' command")
  11983              :face (if has-clippy 'success '(bold warning)))
  11984             (flycheck-verification-result-new
  11985              :label "Cargo.toml"
  11986              :message (if has-toml "Found" "Missing")
  11987              :face (if has-toml 'success '(bold warning))))))))
  11988 
  11989 (flycheck-define-checker salt-lint
  11990   "A salt linter which apply common best practices for SaltStack.
  11991 
  11992 See URL `https://salt-lint.readthedocs.io/en/latest/'."
  11993   :command ("python" "-m" "saltlint" "--json")
  11994   :standard-input t
  11995   :error-parser flycheck-salt-lint-parser
  11996   :error-filter (lambda (errors) (flycheck-sanitize-errors errors))
  11997   :modes salt-mode)
  11998 
  11999 (defun flycheck-salt-lint-parser (output checker buffer)
  12000   "Parse salt lint JSON errors from OUTPUT.
  12001 
  12002 The arguments CHECKER and BUFFER are only passed through."
  12003   (condition-case nil
  12004       (let* ((json-array-type 'list)
  12005              (json-object-type 'plist)
  12006             (filename (buffer-file-name buffer))
  12007             (errors (json-read-from-string output)))
  12008         (mapcar (lambda (e)
  12009                   (flycheck-error-new
  12010                    :checker checker
  12011                    :buffer buffer
  12012                    :filename filename
  12013                    :level (pcase (plist-get e :severity)
  12014                             ("HIGH" 'error)
  12015                             ("MEDIUM" 'warning)
  12016                             ("LOW" 'warning)
  12017                             ("INFO" 'info)
  12018                             (_ 'info))
  12019                    :line (plist-get e :linenumber)
  12020                    :column 0
  12021                    :message (concat (plist-get e :message) (plist-get e :line))
  12022                    :id (plist-get e :id))) errors))
  12023     (json-error nil)))
  12024 
  12025 (defvar flycheck-sass-scss-cache-directory nil
  12026   "The cache directory for `sass' and `scss'.")
  12027 
  12028 (defun flycheck-sass-scss-cache-location ()
  12029   "Get the cache location for `sass' and `scss'.
  12030 
  12031 If no cache directory exists yet, create one and return it.
  12032 Otherwise return the previously used cache directory."
  12033   (setq flycheck-sass-scss-cache-directory
  12034         (or flycheck-sass-scss-cache-directory
  12035             (make-temp-file "flycheck-sass-scss-cache" 'directory))))
  12036 
  12037 (flycheck-def-option-var flycheck-sass-compass nil sass
  12038   "Whether to enable the Compass CSS framework.
  12039 
  12040 When non-nil, enable the Compass CSS framework, via `--compass'."
  12041   :type 'boolean
  12042   :safe #'booleanp
  12043   :package-version '(flycheck . "0.16"))
  12044 
  12045 (flycheck-define-checker sass
  12046   "A Sass syntax checker using the Sass compiler.
  12047 
  12048 See URL `https://sass-lang.com'."
  12049   :command ("sass"
  12050             "--cache-location" (eval (flycheck-sass-scss-cache-location))
  12051             (option-flag "--compass" flycheck-sass-compass)
  12052             "--check" "--stdin")
  12053   :standard-input t
  12054   :error-patterns
  12055   ((error line-start
  12056           (or "Syntax error: " "Error: ")
  12057           (message (one-or-more not-newline)
  12058                    (zero-or-more "\n"
  12059                                  (one-or-more " ")
  12060                                  (one-or-more not-newline)))
  12061           (optional "\r") "\n" (one-or-more " ") "on line " line
  12062           " of standard input"
  12063           line-end)
  12064    (warning line-start
  12065             "WARNING: "
  12066             (message (one-or-more not-newline)
  12067                      (zero-or-more "\n"
  12068                                    (one-or-more " ")
  12069                                    (one-or-more not-newline)))
  12070             (optional "\r") "\n" (one-or-more " ") "on line " line
  12071             " of " (one-or-more not-newline)
  12072             line-end))
  12073   :modes sass-mode)
  12074 
  12075 (flycheck-def-config-file-var flycheck-sass-lintrc sass/scss-sass-lint
  12076                               ".sass-lint.yml"
  12077   :package-version '(flycheck . "30"))
  12078 
  12079 (flycheck-define-checker sass/scss-sass-lint
  12080   "A SASS/SCSS syntax checker using sass-Lint.
  12081 
  12082 See URL `https://github.com/sasstools/sass-lint'."
  12083   :command ("sass-lint"
  12084             "--verbose"
  12085             "--no-exit"
  12086             "--format" "Checkstyle"
  12087             (config-file "--config" flycheck-sass-lintrc)
  12088             source)
  12089   :error-parser flycheck-parse-checkstyle
  12090   :modes (sass-mode scss-mode))
  12091 
  12092 (flycheck-define-checker scala
  12093   "A Scala syntax checker using the Scala compiler.
  12094 
  12095 See URL `https://www.scala-lang.org/'."
  12096   :command ("scalac" "-Ystop-after:parser" source)
  12097   :error-patterns
  12098   ((error line-start (file-name) ":" line ": error: " (message) line-end))
  12099   :modes scala-mode
  12100   :next-checkers ((warning . scala-scalastyle)))
  12101 
  12102 (flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil
  12103   :package-version '(flycheck . "0.20"))
  12104 
  12105 (flycheck-define-checker scala-scalastyle
  12106   "A Scala style checker using scalastyle.
  12107 
  12108 Note that this syntax checker is not used if
  12109 `flycheck-scalastylerc' is nil or refers to a non-existing file.
  12110 
  12111 See URL `https://www.scalastyle.org'."
  12112   :command ("scalastyle"
  12113             (config-file "-c" flycheck-scalastylerc)
  12114             source)
  12115   :error-patterns
  12116   ((error line-start "error file=" (file-name) " message="
  12117           (message) " line=" line (optional " column=" column) line-end)
  12118    (warning line-start "warning file=" (file-name) " message="
  12119             (message) " line=" line (optional " column=" column) line-end))
  12120   :error-filter (lambda (errors)
  12121                   (flycheck-sanitize-errors
  12122                    (flycheck-increment-error-columns errors)))
  12123   :modes scala-mode
  12124   :predicate
  12125   ;; Inhibit this syntax checker if the JAR or the configuration are unset or
  12126   ;; missing
  12127   (lambda () (and flycheck-scalastylerc
  12128                   (flycheck-locate-config-file flycheck-scalastylerc
  12129                                                'scala-scalastyle)))
  12130   :verify (lambda (checker)
  12131             (let ((config-file (and flycheck-scalastylerc
  12132                                     (flycheck-locate-config-file
  12133                                      flycheck-scalastylerc checker))))
  12134               (list
  12135                (flycheck-verification-result-new
  12136                 :label "Configuration file"
  12137                 :message (cond
  12138                           ((not flycheck-scalastylerc)
  12139                            "`flycheck-scalastyletrc' not set")
  12140                           ((not config-file)
  12141                            (format "file %s not found" flycheck-scalastylerc))
  12142                           (t (format "found at %s" config-file)))
  12143                 :face (cond
  12144                        ((not flycheck-scalastylerc) '(bold warning))
  12145                        ((not config-file) '(bold error))
  12146                        (t 'success)))))))
  12147 
  12148 (flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken
  12149   :package-version '(flycheck . "32"))
  12150 
  12151 (flycheck-define-checker scheme-chicken
  12152   "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'.
  12153 
  12154 See URL `https://call-cc.org/'."
  12155   :command ("csc" "-analyze-only" "-local"
  12156             (eval flycheck-scheme-chicken-args)
  12157             source)
  12158   :error-patterns
  12159   ((info line-start
  12160          "Note: " (zero-or-more not-newline) ":\n"
  12161          (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12162          line-end)
  12163    (warning line-start
  12164             "Warning: " (zero-or-more not-newline) ",\n"
  12165             (one-or-more (any space)) (zero-or-more not-newline) ":\n"
  12166             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12167             line-end)
  12168    (warning line-start
  12169             "Warning: " (zero-or-more not-newline) ":\n"
  12170             (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12171             line-end)
  12172    (error line-start "Error: (line " line ") " (message) line-end)
  12173    (error line-start "Syntax error: (" (file-name) ":" line ")"
  12174           (zero-or-more not-newline) " - "
  12175           (message (one-or-more not-newline)
  12176                    (zero-or-more "\n"
  12177                                  (zero-or-more space)
  12178                                  (zero-or-more not-newline))
  12179                    (one-or-more space) "<--")
  12180           line-end)
  12181    ;; A of version 4.12.0, the chicken compiler doesn't provide a
  12182    ;; line number for this error.
  12183    (error line-start "Syntax error: "
  12184           (message (one-or-more not-newline)
  12185                    (zero-or-more "\n"
  12186                                  (zero-or-more space)
  12187                                  (zero-or-more not-newline))
  12188                    (one-or-more space) "<--")
  12189           line-end)
  12190    (error line-start
  12191           "Error: " (zero-or-more not-newline) ":\n"
  12192           (one-or-more (any space)) "(" (file-name) ":" line ") " (message)
  12193           line-end)
  12194    ;; A of version 4.12.0, the chicken compiler doesn't provide a
  12195    ;; line number for this error.
  12196    (error line-start "Error: "
  12197           (message (one-or-more not-newline)
  12198                    (zero-or-more "\n"
  12199                                  (zero-or-more space)
  12200                                  (zero-or-more not-newline))
  12201                    (one-or-more space) "<--")))
  12202   :error-filter flycheck-fill-empty-line-numbers
  12203   :predicate
  12204   (lambda ()
  12205     ;; In `scheme-mode' we must check the current Scheme implementation
  12206     ;; being used
  12207     (and (boundp 'geiser-impl--implementation)
  12208          (eq geiser-impl--implementation 'chicken)))
  12209   :verify
  12210   (lambda (_checker)
  12211     (let ((geiser-impl (bound-and-true-p geiser-impl--implementation)))
  12212       (list
  12213        (flycheck-verification-result-new
  12214         :label "Geiser Implementation"
  12215         :message (cond
  12216                   ((eq geiser-impl 'chicken) "Chicken Scheme")
  12217                   (geiser-impl (format "Other: %s" geiser-impl))
  12218                   (t "Geiser not active"))
  12219         :face (cond
  12220                ((eq geiser-impl 'chicken) 'success)
  12221                (t '(bold error)))))))
  12222   :modes scheme-mode)
  12223 
  12224 (defconst flycheck-scss-lint-checkstyle-re
  12225   (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle")
  12226   "Regular expression to parse missing checkstyle error.")
  12227 
  12228 (defun flycheck-parse-scss-lint (output checker buffer)
  12229   "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER.
  12230 
  12231 Like `flycheck-parse-checkstyle', but catches errors about
  12232 missing checkstyle reporter from SCSS-Lint."
  12233   (if (string-match-p flycheck-scss-lint-checkstyle-re output)
  12234       (list (flycheck-error-new-at
  12235              1 nil 'error "Checkstyle reporter for SCSS-Lint missing.
  12236 Please run gem install scss_lint_reporter_checkstyle"
  12237              :checker checker
  12238              :buffer buffer
  12239              :filename (buffer-file-name buffer)))
  12240     (flycheck-parse-checkstyle output checker buffer)))
  12241 
  12242 (flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml"
  12243   :package-version '(flycheck . "0.23"))
  12244 
  12245 (flycheck-define-checker scss-lint
  12246   "A SCSS syntax checker using SCSS-Lint.
  12247 
  12248 Needs SCSS-Lint 0.43.2 or newer.
  12249 
  12250 See URL `https://github.com/brigade/scss-lint'."
  12251   :command ("scss-lint"
  12252             "--require=scss_lint_reporter_checkstyle"
  12253             "--format=Checkstyle"
  12254             (config-file "--config" flycheck-scss-lintrc)
  12255             "--stdin-file-path" source-original "-")
  12256   :standard-input t
  12257   ;; We cannot directly parse Checkstyle XML, since for some mysterious reason
  12258   ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it
  12259   ;; as an addon which might not be installed.  We use a custom error parser to
  12260   ;; check whether the addon is missing and turn that into a special kind of
  12261   ;; Flycheck error.
  12262   :error-parser flycheck-parse-scss-lint
  12263   :modes scss-mode
  12264   :verify
  12265   (lambda (checker)
  12266     (when-let
  12267         (output (flycheck-call-checker-process-for-output
  12268                  checker nil nil "--require=scss_lint_reporter_checkstyle"))
  12269       (let ((reporter-missing
  12270              (string-match-p flycheck-scss-lint-checkstyle-re output)))
  12271         (list
  12272          (flycheck-verification-result-new
  12273           :label "checkstyle reporter"
  12274           :message (if reporter-missing
  12275                        "scss_lint_reporter_checkstyle plugin missing"
  12276                      "present")
  12277           :face (if reporter-missing
  12278                     '(bold error)
  12279                   'success)))))))
  12280 
  12281 (flycheck-define-checker scss-stylelint
  12282   "A SCSS syntax and style checker using stylelint.
  12283 
  12284 See URL `https://stylelint.io/'."
  12285   :command ("stylelint"
  12286             (eval flycheck-stylelint-args)
  12287             (option-flag "--quiet" flycheck-stylelint-quiet)
  12288             (config-file "--config" flycheck-stylelintrc))
  12289   :standard-input t
  12290   :verify (lambda (_) (flycheck--stylelint-verify 'scss-stylelint))
  12291   :error-parser flycheck-parse-stylelint
  12292   :predicate flycheck-buffer-nonempty-p
  12293   :modes (scss-mode))
  12294 
  12295 (flycheck-define-checker sass-stylelint
  12296   "A Sass syntax and style checker using stylelint.
  12297 
  12298 See URL `https://stylelint.io/'."
  12299   :command ("stylelint"
  12300             (eval flycheck-stylelint-args)
  12301             (option-flag "--quiet" flycheck-stylelint-quiet)
  12302             (config-file "--config" flycheck-stylelintrc))
  12303   :standard-input t
  12304   :verify (lambda (_) (flycheck--stylelint-verify 'sass-stylelint))
  12305   :error-parser flycheck-parse-stylelint
  12306   :predicate flycheck-buffer-nonempty-p
  12307   :modes (sass-mode))
  12308 
  12309 (flycheck-def-option-var flycheck-scss-compass nil scss
  12310   "Whether to enable the Compass CSS framework.
  12311 
  12312 When non-nil, enable the Compass CSS framework, via `--compass'."
  12313   :type 'boolean
  12314   :safe #'booleanp
  12315   :package-version '(flycheck . "0.16"))
  12316 
  12317 (flycheck-define-checker scss
  12318   "A SCSS syntax checker using the SCSS compiler.
  12319 
  12320 See URL `https://sass-lang.com'."
  12321   :command ("scss"
  12322             "--cache-location" (eval (flycheck-sass-scss-cache-location))
  12323             (option-flag "--compass" flycheck-scss-compass)
  12324             "--check" "--stdin")
  12325   :standard-input t
  12326   :error-patterns
  12327   ((error line-start
  12328           (or "Syntax error: " "Error: ")
  12329           (message (one-or-more not-newline)
  12330                    (zero-or-more "\n"
  12331                                  (one-or-more " ")
  12332                                  (one-or-more not-newline)))
  12333           (optional "\r") "\n" (one-or-more " ") "on line " line
  12334           " of standard input"
  12335           line-end)
  12336    (warning line-start
  12337             "WARNING: "
  12338             (message (one-or-more not-newline)
  12339                      (zero-or-more "\n"
  12340                                    (one-or-more " ")
  12341                                    (one-or-more not-newline)))
  12342             (optional "\r") "\n" (one-or-more " ") "on line " line
  12343             " of an unknown file"
  12344             line-end))
  12345   :modes scss-mode)
  12346 
  12347 (flycheck-def-args-var flycheck-sh-bash-args (sh-bash)
  12348   :package-version '(flycheck . "32"))
  12349 
  12350 (flycheck-define-checker sh-bash
  12351   "A Bash syntax checker using the Bash shell.
  12352 
  12353 See URL `https://www.gnu.org/software/bash/'."
  12354   :command ("bash" "--norc" "-n"
  12355             (eval flycheck-sh-bash-args)
  12356             "--")
  12357   :standard-input t
  12358   :error-patterns
  12359   ((error line-start
  12360           ;; The name/path of the bash executable
  12361           (one-or-more (not (any ":"))) ":"
  12362           ;; A label "line", possibly localized
  12363           (one-or-more (not (any digit)))
  12364           line (zero-or-more " ") ":" (zero-or-more " ")
  12365           (message) line-end))
  12366   :modes (sh-mode bash-ts-mode)
  12367   :predicate (lambda () (eq sh-shell 'bash))
  12368   :next-checkers ((warning . sh-shellcheck)))
  12369 
  12370 (flycheck-define-checker sh-posix-dash
  12371   "A POSIX Shell syntax checker using the Dash shell.
  12372 
  12373 See URL `https://gondor.apana.org.au/~herbert/dash/'."
  12374   :command ("dash" "-n")
  12375   :standard-input t
  12376   :error-patterns
  12377   ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message)))
  12378   :modes sh-mode
  12379   :predicate (lambda () (eq sh-shell 'sh))
  12380   :next-checkers ((warning . sh-shellcheck)))
  12381 
  12382 (flycheck-define-checker sh-posix-bash
  12383   "A POSIX Shell syntax checker using the Bash shell.
  12384 
  12385 See URL `https://www.gnu.org/software/bash/'."
  12386   :command ("bash" "--posix" "--norc" "-n" "--")
  12387   :standard-input t
  12388   :error-patterns
  12389   ((error line-start
  12390           ;; The name/path of the bash executable
  12391           (one-or-more (not (any ":"))) ":"
  12392           ;; A label "line", possibly localized
  12393           (one-or-more (not (any digit)))
  12394           line (zero-or-more " ") ":" (zero-or-more " ")
  12395           (message) line-end))
  12396   :modes sh-mode
  12397   :predicate (lambda () (eq sh-shell 'sh))
  12398   :next-checkers ((warning . sh-shellcheck)))
  12399 
  12400 (flycheck-define-checker sh-zsh
  12401   "A Zsh syntax checker using the Zsh shell.
  12402 
  12403 See URL `https://www.zsh.org/'."
  12404   :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source)
  12405   :error-patterns
  12406   ((error line-start (file-name) ":" line ": " (message) line-end))
  12407   :modes sh-mode
  12408   :predicate (lambda () (eq sh-shell 'zsh))
  12409   :next-checkers ((warning . sh-shellcheck)))
  12410 
  12411 (defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh)
  12412   "Shells supported by ShellCheck.")
  12413 
  12414 (flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck
  12415   "A list of excluded warnings for ShellCheck.
  12416 
  12417 The value of this variable is a list of strings, where each
  12418 string is a warning code to be excluded from ShellCheck reports.
  12419 By default, no warnings are excluded."
  12420   :type '(repeat :tag "Excluded warnings"
  12421                  (string :tag "Warning code"))
  12422   :safe #'flycheck-string-list-p
  12423   :package-version '(flycheck . "0.21"))
  12424 
  12425 (flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck
  12426   "Whether to follow external sourced files in scripts.
  12427 
  12428 Shellcheck will follow and parse sourced files so long as a
  12429 pre-runtime resolvable path to the file is present.  This can
  12430 either be part of the source command itself:
  12431    source /full/path/to/file.txt
  12432 or added as a shellcheck directive before the source command:
  12433    # shellcheck source=/full/path/to/file.txt."
  12434   :type 'boolean
  12435   :safe #'booleanp
  12436   :package-version '(flycheck . "31"))
  12437 
  12438 (flycheck-define-checker sh-shellcheck
  12439   "A shell script syntax and style checker using Shellcheck.
  12440 
  12441 See URL `https://github.com/koalaman/shellcheck/'."
  12442   :command ("shellcheck"
  12443             "--format" "checkstyle"
  12444             "--shell" (eval (symbol-name sh-shell))
  12445             (option-flag "--external-sources"
  12446                          flycheck-shellcheck-follow-sources)
  12447             (option "--exclude" flycheck-shellcheck-excluded-warnings list
  12448                     flycheck-option-comma-separated-list)
  12449             "-")
  12450   :standard-input t
  12451   :error-parser flycheck-parse-checkstyle
  12452   :error-filter
  12453   (lambda (errors)
  12454     (flycheck-remove-error-file-names
  12455      "-" (flycheck-dequalify-error-ids errors)))
  12456   :modes (sh-mode bash-ts-mode)
  12457   :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells))
  12458   :verify (lambda (_)
  12459             (let ((supports-shell (memq sh-shell
  12460                                         flycheck-shellcheck-supported-shells)))
  12461               (list
  12462                (flycheck-verification-result-new
  12463                 :label (format "Shell %s supported" sh-shell)
  12464                 :message (if supports-shell "yes" "no")
  12465                 :face (if supports-shell 'success '(bold warning))))))
  12466   :error-explainer
  12467   (lambda (err)
  12468     (let ((error-code (flycheck-error-id err))
  12469           (url "https://github.com/koalaman/shellcheck/wiki/%s"))
  12470       (and error-code `(url . ,(format url error-code))))))
  12471 
  12472 (flycheck-define-checker slim
  12473   "A Slim syntax checker using the Slim compiler.
  12474 
  12475 See URL `https://slim-lang.com'."
  12476   :command ("slimrb" "--compile")
  12477   :standard-input t
  12478   :error-patterns
  12479   ((error line-start
  12480           "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n  "
  12481           "STDIN, Line " line (optional ", Column " column)
  12482           line-end))
  12483   :modes slim-mode
  12484   :next-checkers ((warning . slim-lint)))
  12485 
  12486 (flycheck-define-checker slim-lint
  12487   "A Slim linter.
  12488 
  12489 See URL `https://github.com/sds/slim-lint'."
  12490   :command ("slim-lint" "--reporter=checkstyle" source)
  12491   :error-parser flycheck-parse-checkstyle
  12492   :modes slim-mode)
  12493 
  12494 (flycheck-define-checker sql-sqlint
  12495   "A SQL syntax checker using the sqlint tool.
  12496 
  12497 See URL `https://github.com/purcell/sqlint'."
  12498   :command ("sqlint")
  12499   :standard-input t
  12500   :error-patterns
  12501   ((warning line-start "stdin:" line ":" column ":WARNING "
  12502             (message (one-or-more not-newline)
  12503                      (zero-or-more "\n"
  12504                                    (one-or-more "  ")
  12505                                    (one-or-more not-newline)))
  12506             line-end)
  12507    (error line-start "stdin:" line ":" column ":ERROR "
  12508           (message (one-or-more not-newline)
  12509                    (zero-or-more "\n"
  12510                                  (one-or-more "  ")
  12511                                  (one-or-more not-newline)))
  12512           line-end))
  12513   :modes (sql-mode))
  12514 
  12515 (flycheck-define-checker systemd-analyze
  12516   "A systemd unit checker using systemd-analyze(1).
  12517 
  12518 See URL
  12519 `https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'."
  12520   :command ("systemd-analyze" "verify" source)
  12521   :error-parser flycheck-parse-with-patterns-without-color
  12522   :error-patterns
  12523   ((error line-start (file-name) ":" (optional line ":") (message) line-end)
  12524    (error line-start "[" (file-name) ":" line "]" (message) line-end))
  12525   :error-filter (lambda (errors)
  12526                   (flycheck-sanitize-errors
  12527                    (flycheck-fill-empty-line-numbers errors)))
  12528   :modes (systemd-mode))
  12529 
  12530 (flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc")
  12531 
  12532 (flycheck-define-checker tcl-nagelfar
  12533   "An extensible tcl syntax checker
  12534 
  12535 See URL `https://nagelfar.sourceforge.net/'."
  12536   :command ("nagelfar" "-H" source)
  12537   :error-patterns
  12538   ;; foo.tcl: 29: E Wrong number of arguments (4) to "set"
  12539   ;; foo.tcl: 29: W Expr without braces
  12540   ((info    line-start (file-name) ": " line ": N " (message) line-end)
  12541    (warning line-start (file-name) ": " line ": W " (message) line-end)
  12542    (error   line-start (file-name) ": " line ": E " (message) line-end))
  12543   :modes tcl-mode)
  12544 
  12545 (flycheck-define-checker terraform
  12546   "A Terraform syntax checker with `terraform fmt'.
  12547 
  12548 See URL `https://www.terraform.io/docs/commands/fmt.html'."
  12549   :command ("terraform" "fmt" "-no-color" "-")
  12550   :standard-input t
  12551   :error-patterns
  12552   ((error line-start "Error: " (one-or-more not-newline)
  12553           "\n\n  on <stdin> line " line ", in " (one-or-more not-newline) ":"
  12554           (one-or-more "\n" (zero-or-more space (one-or-more not-newline)))
  12555           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
  12556           line-end)
  12557    (error line-start "Error: " (one-or-more not-newline)
  12558           "\n\n  on <stdin> line " line ":\n  (source code not available)\n\n"
  12559           (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n)))
  12560           line-end))
  12561   :next-checkers ((warning . terraform-tflint))
  12562   :modes terraform-mode)
  12563 
  12564 (flycheck-def-option-var flycheck-tflint-variable-files nil terraform-tflint
  12565   "A list of files to resolve terraform variables.
  12566 
  12567 The value of this variable is a list of strings, where each
  12568 string is a file to add to the terraform variables files.
  12569 Relative files are relative to the file being checked."
  12570   :type '(repeat (directory :tag "Variable file"))
  12571   :safe #'flycheck-string-list-p
  12572   :package-version '(flycheck . "32"))
  12573 
  12574 (defun flycheck-parse-tflint-linter (output checker buffer)
  12575   "Parse tflint warnings from JSON OUTPUT.
  12576 
  12577 CHECKER and BUFFER denote the CHECKER that returned OUTPUT and
  12578 the BUFFER that was checked respectively.
  12579 
  12580 See URL `https://github.com/terraform-linters/tflint' for more
  12581 information about tflint."
  12582   (mapcar (lambda (err)
  12583             (let-alist err
  12584               (flycheck-error-new-at
  12585                .range.start.line
  12586                .range.start.column
  12587                (pcase .rule.severity
  12588                  ("error"   'error)
  12589                  ("warning" 'warning)
  12590                  (_         'error))
  12591                .message
  12592                :end-line .range.end.line
  12593                :end-column .range.end.column
  12594                :id .rule.name
  12595                :checker checker
  12596                :buffer buffer
  12597                :filename (buffer-file-name buffer))))
  12598           (cdr (assq 'issues (car (flycheck-parse-json output))))))
  12599 
  12600 (flycheck-define-checker terraform-tflint
  12601   "A Terraform checker using tflint.
  12602 
  12603 See URL `https://github.com/terraform-linters/tflint'."
  12604   :command ("tflint" "--format=json" "--force"
  12605             (option-list "--var-file=" flycheck-tflint-variable-files concat))
  12606   :error-parser flycheck-parse-tflint-linter
  12607   :predicate flycheck-buffer-saved-p
  12608   :modes terraform-mode)
  12609 
  12610 (flycheck-def-option-var flycheck-chktex-extra-flags nil tex-chktex
  12611   "A list of extra arguments to give to chktex.
  12612 This variable works the same way as `tex-chktex-extra-flags': its value
  12613 is a list of strings, where each string is an argument added to chktex.
  12614 
  12615 For example, to ignore warnings 8 and 18, you would set this option to
  12616 
  12617   \\='(\"-n8\" \"-n18\")."
  12618   :type '(repeat string)
  12619   :safe #'flycheck-string-list-p
  12620   :package-version '(flycheck . "35"))
  12621 
  12622 (flycheck-define-checker tex-chktex
  12623   "A TeX and LaTeX syntax and style checker using chktex.
  12624 
  12625 See URL `https://www.nongnu.org/chktex/'."
  12626   :command ("chktex"
  12627             (config-file "--localrc" flycheck-chktexrc)
  12628             (option-list "" flycheck-chktex-extra-flags concat)
  12629             ;; Compact error messages, and no version information, and execute
  12630             ;; \input statements
  12631             "--verbosity=0" "--quiet" "--inputfiles")
  12632   :standard-input t
  12633   :error-patterns
  12634   ((warning line-start "stdin:" line ":" column ":"
  12635             (id (one-or-more digit)) ":" (message) line-end))
  12636   :error-filter
  12637   (lambda (errors)
  12638     (flycheck-sanitize-errors (flycheck-increment-error-columns errors)))
  12639   :modes (latex-mode LaTeX-mode plain-tex-mode plain-TeX-mode))
  12640 
  12641 (flycheck-define-checker tex-lacheck
  12642   "A LaTeX syntax and style checker using lacheck.
  12643 
  12644 See URL `https://www.ctan.org/pkg/lacheck'."
  12645   :command ("lacheck" source-inplace)
  12646   :error-patterns
  12647   ((warning line-start
  12648             "\"" (file-name) "\", line " line ": " (message)
  12649             line-end))
  12650   :modes (latex-mode LaTeX-mode))
  12651 
  12652 (flycheck-define-checker texinfo
  12653   "A Texinfo syntax checker using makeinfo.
  12654 
  12655 See URL `https://www.gnu.org/software/texinfo/'."
  12656   :command ("makeinfo" "-o" null-device "-")
  12657   :standard-input t
  12658   :error-patterns
  12659   ((warning line-start
  12660             "-:" line (optional ":" column) ": " "warning: " (message)
  12661             line-end)
  12662    (error line-start
  12663           "-:" line (optional ":" column) ": " (message)
  12664           line-end))
  12665   :modes (texinfo-mode Texinfo-mode))
  12666 
  12667 (flycheck-def-config-file-var flycheck-textlint-config
  12668     textlint "textlintrc.json")
  12669 
  12670 ;; This needs to be set because textlint plugins are installed separately,
  12671 ;; and there is no way to check their installation status -- textlint simply
  12672 ;; prints a backtrace.
  12673 (flycheck-def-option-var flycheck-textlint-plugin-alist
  12674     '((markdown-mode . "@textlint/markdown")
  12675       (gfm-mode . "@textlint/markdown")
  12676       (t . "@textlint/text"))
  12677     textlint
  12678   "An alist mapping major modes to textlint plugins.
  12679 
  12680 Each item is a cons cell `(MAJOR-MODE . PLUGIN)', where MAJOR-MODE is a mode
  12681 `flycheck-textlint' supports and PLUGIN is a textlint plugin. As a catch-all,
  12682 when MAJOR-MODE is t, that PLUGIN will be used for any supported mode that
  12683 isn't specified.
  12684 
  12685 See URL `https://npms.io/search?q=textlint-plugin' for all textlint plugins
  12686 published on NPM."
  12687   :type '(repeat (choice (cons symbol string)
  12688                          (cons (const t) string))))
  12689 
  12690 (defun flycheck--textlint-get-plugin ()
  12691   "Return the textlint plugin for the current mode."
  12692   (cdr (seq-find
  12693         (lambda (arg)
  12694           (pcase-let ((`(,mode . _) arg))
  12695             (or (and (booleanp mode) mode) ; mode is t
  12696                 (derived-mode-p mode))))
  12697         flycheck-textlint-plugin-alist)))
  12698 
  12699 (flycheck-define-checker textlint
  12700   "A text prose linter using textlint.
  12701 
  12702 See URL `https://textlint.github.io/'."
  12703   :command ("textlint"
  12704             (config-file "--config" flycheck-textlint-config)
  12705             "--format" "json"
  12706             ;; get the first matching plugin from plugin-alist
  12707             "--plugin"
  12708             (eval (flycheck--textlint-get-plugin))
  12709             source)
  12710   ;; textlint seems to say that its json output is compatible with ESLint.
  12711   ;; https://textlint.github.io/docs/formatter.html
  12712   :error-parser flycheck-parse-eslint
  12713   ;; textlint can support different formats with textlint plugins, but
  12714   ;; only text and markdown formats are installed by default. Ask the
  12715   ;; user to add mode->plugin mappings manually in
  12716   ;; `flycheck-textlint-plugin-alist'.
  12717   :modes
  12718   (text-mode markdown-mode gfm-mode message-mode adoc-mode
  12719              mhtml-mode latex-mode LaTeX-mode org-mode rst-mode)
  12720   :enabled
  12721   (lambda () (flycheck--textlint-get-plugin))
  12722   :verify
  12723   (lambda (_)
  12724     (let ((plugin (flycheck--textlint-get-plugin)))
  12725       (list
  12726        (flycheck-verification-result-new
  12727         :label "textlint plugin"
  12728         :message plugin
  12729         :face 'success)))))
  12730 
  12731 (flycheck-def-config-file-var flycheck-typescript-tslint-config
  12732     typescript-tslint "tslint.json"
  12733   :package-version '(flycheck . "27"))
  12734 
  12735 (flycheck-def-option-var flycheck-typescript-tslint-rulesdir
  12736     nil typescript-tslint
  12737   "The directory of custom rules for TSLint.
  12738 
  12739 The value of this variable is either a string containing the path
  12740 to a directory with custom rules, or nil, to not give any custom
  12741 rules to TSLint.
  12742 
  12743 Refer to the TSLint manual at URL
  12744 `https://palantir.github.io/tslint/usage/cli/'
  12745 for more information about the custom directory."
  12746   :type '(choice (const :tag "No custom rules directory" nil)
  12747                  (directory :tag "Custom rules directory"))
  12748   :safe #'flycheck-string-or-nil-p
  12749   :package-version '(flycheck . "27"))
  12750 
  12751 (flycheck-def-args-var flycheck-tslint-args (typescript-tslint)
  12752   :package-version '(flycheck . "31"))
  12753 
  12754 (flycheck-define-checker typescript-tslint
  12755   "TypeScript style checker using TSLint.
  12756 
  12757 Note that this syntax checker is not used if
  12758 `flycheck-typescript-tslint-config' is nil or refers to a
  12759 non-existing file.
  12760 
  12761 See URL `https://github.com/palantir/tslint'."
  12762   :command ("tslint" "--format" "json"
  12763             (config-file "--config" flycheck-typescript-tslint-config)
  12764             (option "--rules-dir" flycheck-typescript-tslint-rulesdir)
  12765             (eval flycheck-tslint-args)
  12766             source-inplace)
  12767   :error-parser flycheck-parse-tslint
  12768   :modes (typescript-mode typescript-ts-mode tsx-ts-mode))
  12769 
  12770 (flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator
  12771   "A list of include directories for Verilator.
  12772 
  12773 The value of this variable is a list of strings, where each
  12774 string is a directory to add to the include path of Verilator.
  12775 Relative paths are relative to the file being checked."
  12776   :type '(repeat (directory :tag "Include directory"))
  12777   :safe #'flycheck-string-list-p
  12778   :package-version '(flycheck . "0.24"))
  12779 
  12780 (flycheck-define-checker verilog-verilator
  12781   "A Verilog syntax checker using the Verilator Verilog HDL simulator.
  12782 
  12783 See URL `https://www.veripool.org/wiki/verilator'."
  12784   :command ("verilator" "--lint-only" "-Wall" "--quiet-exit"
  12785             (option-list "-I" flycheck-verilator-include-path concat)
  12786             source)
  12787   :error-patterns
  12788   ((warning line-start "%Warning"
  12789             (? "-" (id (+ (any "0-9A-Z_")))) ": "
  12790             (? (file-name) ":" line ":" (? column ":") " ")
  12791             (message) line-end)
  12792    (error line-start "%Error"
  12793           (? "-" (id (+ (any "0-9A-Z_")))) ": "
  12794           (? (file-name) ":" line ":" (? column ":") " ")
  12795           (message) line-end))
  12796   :modes verilog-mode)
  12797 
  12798 (flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl
  12799   "The language standard to use in GHDL.
  12800 
  12801 The value of this variable is either a string denoting a language
  12802 standard, or nil, to use the default standard.  When non-nil,
  12803 pass the language standard via the `--std' option."
  12804   :type '(choice (const :tag "Default standard" nil)
  12805                  (string :tag "Language standard"))
  12806   :safe #'flycheck-string-or-nil-p
  12807   :package-version '(flycheck . "32"))
  12808 (make-variable-buffer-local 'flycheck-ghdl-language-standard)
  12809 
  12810 (flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl
  12811   "The directory to use for the file library.
  12812 
  12813 The value of this variable is either a string with the directory
  12814 to use for the file library, or nil, to use the default value.
  12815 When non-nil, pass the directory via the `--workdir' option."
  12816   :type '(choice (const :tag "Default directory" nil)
  12817                  (string :tag "Directory for the file library"))
  12818   :safe #'flycheck-string-or-nil-p
  12819   :package-version '(flycheck . "32"))
  12820 (make-variable-buffer-local 'flycheck-ghdl-workdir)
  12821 
  12822 (flycheck-def-option-var flycheck-ghdl-ieee-library nil vhdl-ghdl
  12823   "The standard to use for the IEEE library.
  12824 
  12825 The value of this variable is either a string denoting an ieee library
  12826 standard, or nil, to use the default standard.  When non-nil,
  12827 pass the ieee library standard via the `--ieee' option."
  12828   :type '(choice (const :tag "Default standard" nil)
  12829                  (const :tag "No IEEE Library" "none")
  12830                  (const :tag "IEEE standard" "standard")
  12831                  (const :tag "Synopsys standard" "synopsys")
  12832                  (const :tag "Mentor standard" "mentor"))
  12833   :safe #'flycheck-string-or-nil-p
  12834   :package-version '(flycheck . "32"))
  12835 (make-variable-buffer-local 'flycheck-ghdl-ieee-library)
  12836 
  12837 (flycheck-define-checker vhdl-ghdl
  12838   "A VHDL syntax checker using GHDL.
  12839 
  12840 See URL `https://github.com/ghdl/ghdl'."
  12841   :command ("ghdl"
  12842             "-s" ; only do the syntax checking
  12843             (option "--std=" flycheck-ghdl-language-standard concat)
  12844             (option "--workdir=" flycheck-ghdl-workdir concat)
  12845             (option "--ieee=" flycheck-ghdl-ieee-library concat)
  12846             source)
  12847   :error-patterns
  12848   ((warning line-start (file-name) ":" line ":" column ":warning: " (message) line-end)
  12849    (error line-start (file-name) ":" line ":" column ":error: " (message) line-end))
  12850   :modes vhdl-mode)
  12851 
  12852 (flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet
  12853   "An XSD schema to validate against."
  12854   :type '(choice (const :tag "None" nil)
  12855                  (file :tag "XSD schema"))
  12856   :safe #'flycheck-string-or-nil-p
  12857   :package-version '(flycheck . "31"))
  12858 
  12859 (flycheck-define-checker xml-xmlstarlet
  12860   "A XML syntax checker and validator using the xmlstarlet utility.
  12861 
  12862 See URL `https://xmlstar.sourceforge.net/'."
  12863   ;; Validate standard input with verbose error messages, and do not dump
  12864   ;; contents to standard output
  12865   :command ("xmlstarlet" "val" "--err" "--quiet"
  12866             (option "--xsd" flycheck-xml-xmlstarlet-xsd-path)
  12867             "-")
  12868   :standard-input t
  12869   :error-patterns
  12870   ((error line-start "-:" line "." column ": " (message) line-end))
  12871   :modes (xml-mode nxml-mode))
  12872 
  12873 (flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint
  12874   "An XSD schema to validate against."
  12875   :type '(choice (const :tag "None" nil)
  12876                  (file :tag "XSD schema"))
  12877   :safe #'flycheck-string-or-nil-p
  12878   :package-version '(flycheck . "31"))
  12879 
  12880 (flycheck-def-option-var flycheck-xml-xmllint-relaxng-path nil xml-xmllint
  12881   "An RELAX NG schema to validate against."
  12882   :type '(choice (const :tag "None" nil)
  12883                  (file :tag "RELAX NG schema"))
  12884   :safe #'flycheck-string-or-nil-p
  12885   :package-version '(flycheck . "34"))
  12886 
  12887 (flycheck-define-checker xml-xmllint
  12888   "A XML syntax checker and validator using the xmllint utility.
  12889 
  12890 The xmllint is part of libxml2, see URL
  12891 `https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home'."
  12892   :command ("xmllint" "--noout"
  12893             (option "--schema" flycheck-xml-xmllint-xsd-path)
  12894             (option "--relaxng" flycheck-xml-xmllint-relaxng-path)
  12895             "-")
  12896   :standard-input t
  12897   :error-patterns
  12898   ((error line-start "-:" line ": " (message) line-end))
  12899   :modes (xml-mode nxml-mode))
  12900 
  12901 (flycheck-define-checker yaml-jsyaml
  12902   "A YAML syntax checker using JS-YAML.
  12903 
  12904 See URL `https://github.com/nodeca/js-yaml'."
  12905   :command ("js-yaml")
  12906   :standard-input t
  12907   :error-patterns
  12908   ((error line-start
  12909           (or "JS-YAML" "YAMLException") ": "
  12910           (message) " at line " line ", column " column ":"
  12911           line-end)
  12912    (error line-start
  12913           (or "JS-YAML" "YAMLException") ": "
  12914           (message) " (" line ":" column ")"
  12915           line-end))
  12916   :modes (yaml-mode yaml-ts-mode)
  12917   :next-checkers ((warning . yaml-yamllint)
  12918                   (warning . cwl)))
  12919 
  12920 (flycheck-define-checker yaml-ruby
  12921   "A YAML syntax checker using Ruby's YAML parser.
  12922 
  12923 This syntax checker uses the YAML parser from Ruby's standard
  12924 library.
  12925 
  12926 See URL `https://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'."
  12927   :command ("ruby" "-ryaml" "-e" "begin;
  12928    YAML.load(STDIN); \
  12929  rescue Exception => e; \
  12930    STDERR.puts \"stdin:#{e}\"; \
  12931  end")
  12932   :standard-input t
  12933   :error-patterns
  12934   ((error line-start "stdin:" (zero-or-more not-newline) ":" (message)
  12935           "at line " line " column " column line-end))
  12936   :modes (yaml-mode yaml-ts-mode)
  12937   :next-checkers ((warning . yaml-yamllint)
  12938                   (warning . cwl)))
  12939 
  12940 (flycheck-def-config-file-var flycheck-yamllintrc
  12941     yaml-yamllint
  12942     '(".yamllint"
  12943       ".yamllint.yaml"
  12944       ".yamllint.yml"
  12945       "~/.config/yamllint/config"))
  12946 
  12947 (flycheck-define-checker yaml-yamllint
  12948   "A YAML syntax checker using YAMLLint.
  12949 See URL `https://github.com/adrienverge/yamllint'."
  12950   :standard-input t
  12951   :command ("yamllint" "-f" "parsable" "-"
  12952             (config-file "-c" flycheck-yamllintrc))
  12953   :error-patterns
  12954   ((error line-start
  12955           "stdin:" line ":" column ": [error] " (message) line-end)
  12956    (warning line-start
  12957             "stdin:" line ":" column ": [warning] " (message) line-end))
  12958   :modes (yaml-mode yaml-ts-mode)
  12959   :next-checkers ((warning . cwl)))
  12960 
  12961 (provide 'flycheck)
  12962 
  12963 ;; Local Variables:
  12964 ;; coding: utf-8
  12965 ;; indent-tabs-mode: nil
  12966 ;; End:
  12967 
  12968 ;;; flycheck.el ends here