commit 26c746221bf6aef611caffdfa794b484c2719ad2 Author: brettlangdon Date: Sun Jan 24 09:51:31 2021 -0500 Squashed 'emacs.d/vendor/flycheck/' content from commit 01396a5e git-subtree-dir: emacs.d/vendor/flycheck git-subtree-split: 01396a5eff9fa494285e0d3139838231c05e3948 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..7dc5e16 --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +# -*- mode: conf; -*- +[flake8] +# Ignore all missing docstrings for now, until we have docstrings everywhere +ignore = D100,D101,D102,D103,D105,D401,W503 +exclude = test/resources +inline-quotes = ' diff --git a/.github/CLA.md b/.github/CLA.md new file mode 100644 index 0000000..6b7f82e --- /dev/null +++ b/.github/CLA.md @@ -0,0 +1,7 @@ +I, the contributor, agree to licence my contributions to the Flycheck project +under the terms of the [GPL 3.0][1] and any later version, and to license my +contributions to the documentation of the Flycheck project under the terms of +the [Creative Commons Attribution-ShareAlike 4.0 International][2] license. + +[1]: http://www.flycheck.org/en/latest/licenses.html#flycheck-gpl +[2]: http://www.flycheck.org/en/latest/licenses.html#flycheck-cc-by-sa diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst new file mode 100644 index 0000000..a543317 --- /dev/null +++ b/.github/CONTRIBUTING.rst @@ -0,0 +1,14 @@ +=========== + Thank you +=========== + +Thank you very much for your interest in contributing to Flycheck! We’d like to +warmly welcome you in the Flycheck community, and hope that you enjoy your time +with us! + +Flycheck’s documentation provides a comprehensive Contributor Guide which shows +how you can contribute to Flycheck and helps you through all stages of the +contribution process. + +Please read it at +. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..f861f9e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,47 @@ +--- +name: Bug report +about: Report an unexpected Flycheck behavior +title: '' +labels: 'kind: bug' +assignees: '' + +--- + +Thank you for taking the time to report an issue and improve Flycheck. This template is for **actual bugs you observed**. If you have trouble setting up Flycheck, or if you have a question, please use the relevant issue template instead. + +## Checklist +- [ ] I have checked existing issues for potential duplicates before creating this one. +- [ ] I have read the [Troubleshooting guide][]. + +## Bug description +A clear and concise description of what the bug is. + +## Steps to reproduce +Steps to reproduce the behavior: +1. Open file '...' +2. Do '....' +3. See error + +- [ ] I have read https://emacs.stackexchange.com/questions/28429/how-do-i-troubleshoot-emacs-problems + +## Expected behavior +A clear and concise description of what you expected to happen. + +## Screenshots +If applicable, add screenshots to help explain your problem. + +## System configuration +``` +Paste the output of `M-x flycheck-verify-setup` here. +``` + +Emacs configuration: +- [ ] Plain Emacs / Custom configuration +- [ ] Spacemacs +- [ ] Doom Emacs +- [ ] Other shared configuration + +## Additional notes +Add any other context about the problem here. + +[Troubleshooting guide]: https://www.flycheck.org/en/latest/user/troubleshooting.html diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..d1bd898 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,22 @@ +--- +name: Feature request +about: Suggest an improvement to Flycheck +title: '' +labels: 'kind: feature request' +assignees: '' + +--- + +Thank you for taking the time to improve Flycheck. + +## Checklist +- [ ] I have checked existing issues for potential duplicates before creating this one. + +## Feature description +A clear and concise description of what you want Flycheck to do. + +## Describe alternatives you've considered +A clear and concise description of any alternative solutions or features you've considered. + +## Additional context +Add any other context or screenshots, mockups etc. diff --git a/.github/ISSUE_TEMPLATE/user-support.md b/.github/ISSUE_TEMPLATE/user-support.md new file mode 100644 index 0000000..7fc6e2c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/user-support.md @@ -0,0 +1,50 @@ +--- +name: User support +about: Trouble setting up or using Flycheck? +title: '' +labels: 'kind: user support' +assignees: '' + +--- + +This template is for **user support**. If you are reporting an actual Flycheck bug, please use the relevant issue template instead. + +## Checklist +- [ ] I have searched existing issues and StackOverflow for solutions. +- [ ] I have read the [Flycheck manual][]. +- [ ] I have read the [Troubleshooting Guide][]. +- [ ] I have checked my issue has not been reported yet. + +## Problem description +A clear and concise description of the problem you encounter. + +## Steps to reproduce +Steps to reproduce the behavior: +1. Open file '...' +2. Do '....' +3. See error + +- [ ] I have read https://emacs.stackexchange.com/questions/28429/how-do-i-troubleshoot-emacs-problems + +## Expected behavior +A clear and concise description of what you expected to happen. + +## Screenshots +If applicable, add screenshots to help explain your problem. + +## System configuration +``` +Paste the output of `M-x flycheck-verify-setup` here. +``` + +Emacs configuration: +- [ ] Plain Emacs / Custom configuration +- [ ] Spacemacs +- [ ] Doom Emacs +- [ ] Other shared configuration + +## Additional notes +Add any other context about the problem here. + +[Flycheck manual]: https://www.flycheck.org/en/latest/user/troubleshooting.html +[Troubleshooting guide]: https://www.flycheck.org/en/latest/user/troubleshooting.html diff --git a/.github/PULL_REQUEST_TEMPLATE/new-checker.md b/.github/PULL_REQUEST_TEMPLATE/new-checker.md new file mode 100644 index 0000000..d93c6bf --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/new-checker.md @@ -0,0 +1,28 @@ +--- +name: New checker +about: Provide a new checker implementation +title: 'Add syntax checker for XXX' +labels: 'component: checkers' +assignees: '' + +--- + +## Checklist +- [ ] I have read the [Contributor's guide][]. +- [ ] I have documented this checker in the [manual][]. +- [ ] I have added a test for this checker in [flycheck-test.el][]. +- [ ] (*If you have written a test*) I have created a companion PR to add the + checker tool in [flycheck/docker-tools][]. +- [ ] I have mentioned the checker in the [Changelog][]. + +## Description +Describe the checker you added. + +## Additional context +Additional relevant information about the checker and its integration into Flycheck. + +[Changelog]: https://github.com/flycheck/flycheck/blob/master/CHANGES.rst +[manual]: https://www.flycheck.org/en/latest/languages.html +[flycheck-test.el]: https://github.com/flycheck/flycheck/blob/master/test/flycheck-test.el +[flycheck/docker-tools]: https://github.com/flycheck/docker-tools +[Contributor's guide]: https://www.flycheck.org/en/latest/contributor/contributing.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..562f42b --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.elc + +# Packages installed for development +/.cask/ + +# Bundler configuration and lock file +/.bundle/ +/Gemfile.lock + +# Generated distribution packages +/dist/ + +# Directory local variables +.dir-locals.el diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..320bbc9 --- /dev/null +++ b/.mailmap @@ -0,0 +1,32 @@ +# -*- mode: conf; -*- + +Biao Xie <423300@gmail.com> +Bozhidar Batsov +Chao SHEN +Cristian Capdevila +Manuel Uberti +Manuel Uberti +Mark Hellewell +Mark Karpov +Peter Vasil +Romanos Skiadas +# Looks as if there's different unicode normalisations for this name +Saša Jovanić +Sean Whitton +Sebastian Schueppel +Sebastian Wiesner +Sebastian Wiesner +Senda Akiha +Steve Purcell +Sylvain Benner +Sylvain Rousseau +Vlatko Basic +Yuuki Arisawa +Zhuo Yuan + +# These contributors prefer to remain anonymous +fmdkdd + +# The real names of these contributors are unknown +papaeye +chessman diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5857295 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,96 @@ +# Use Python 3.5 for our tooling +language: python +python: +- "3.8" + +# Our tests are run with Emacs in Docker +services: +- docker + +matrix: + # Don’t wait for jobs that are allowed to fail + fast_finish: true + # Allow master branch to fail + allow_failures: + - env: JOB="emacs" EMACS_VERSION="master" + +cache: +- pip + +env: + matrix: + # Run our tests on all these Emacs versions + - JOB="emacs" EMACS_VERSION="master" + - JOB="emacs" EMACS_VERSION="27.1" + - JOB="emacs" EMACS_VERSION="26.3" + - JOB="emacs" EMACS_VERSION="25.3" + # A special job to build the manual + - JOB="build-manual" + # And another special job to lint our Python code + - JOB="lint-python" + +before_install: +- if [[ $JOB == emacs ]]; then docker pull flycheck/emacs-cask:$EMACS_VERSION; fi + +install: +- | + case $JOB in + emacs) + # We use separate Cask files for Emacs 25 + if [[ $EMACS_VERSION == 25.* ]]; then + cp Cask.25 Cask + fi + # Install Emacs modes for our tests + docker run --volume "$TRAVIS_BUILD_DIR":/flycheck \ + --workdir /flycheck \ + flycheck/emacs-cask:$EMACS_VERSION \ + /bin/bash -c "make init";; + build-manual) + # Install requirements of documentation + pip install -r doc/requirements.txt;; + lint-python) + # Install requirements for linting + pip install -r maint/requirements.txt;; + esac + +script: +- | + # Abort if any command fails + set -e + case $JOB in + emacs) + # Check formatting + docker run --volume "$TRAVIS_BUILD_DIR":/flycheck \ + --workdir /flycheck \ + flycheck/emacs-cask:$EMACS_VERSION \ + /bin/bash -c "make check" + # Compile and run unit tests. + docker run --volume "$TRAVIS_BUILD_DIR":/flycheck \ + --workdir /flycheck \ + flycheck/emacs-cask:$EMACS_VERSION \ + /bin/bash -c "make compile && make unit && make specs" + # If the unit tests succeed, fetch the all-tools container + # and run the integration tests + docker build --build-arg EMACS_VERSION=$EMACS_VERSION \ + --tag tools-and-emacs:$EMACS_VERSION \ + --file=.travis/tools-and-emacs . + docker run --volume "$TRAVIS_BUILD_DIR":/flycheck \ + --workdir /flycheck \ + tools-and-emacs:$EMACS_VERSION \ + /bin/bash -c "check-tools && make integ" ;; + + build-manual) + # Build and deploy the manual + make -C doc SPHINXOPTS=-n html;; + + lint-python) + # Lint our Python code + make -C maint check;; + + esac + +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/efdc5fd9433efa7c6b80 + on_success: change diff --git a/.travis/tools-and-emacs b/.travis/tools-and-emacs new file mode 100644 index 0000000..b825625 --- /dev/null +++ b/.travis/tools-and-emacs @@ -0,0 +1,22 @@ +# Adding this stage is a workaround because `COPY --from` does not support +# variable substitution. +# See https://github.com/moby/moby/issues/34482 +ARG EMACS_VERSION=25.3 +FROM flycheck/emacs-cask:${EMACS_VERSION} AS emacs-cask + +FROM flycheck/all-tools + +# We need gnutls for downloading packages from ELPA +RUN apt-get -qq update && \ + apt-get install -qq --no-install-recommends -y \ + gnutls-bin \ + make \ + && rm -rf /var/lib/apt/lists/* + +# We need Emacs and Cask +ENV PATH /opt/emacs/bin:$PATH +COPY --from=emacs-cask /opt/emacs /opt/emacs + +ENV PATH /root/.cask/bin:$PATH +COPY --from=emacs-cask /root/.cask /root/.cask +COPY --from=emacs-cask /root/.emacs.d /root/.emacs.d diff --git a/CHANGES.old b/CHANGES.old new file mode 100644 index 0000000..ca3b053 --- /dev/null +++ b/CHANGES.old @@ -0,0 +1,1050 @@ +0.25.1 (Nov 16, 2015) +--------------------- + +- Fix undefined function call in ``emacs-lisp`` syntax checker [GH-791] + +0.25 (Nov 14, 2015) +------------------- + +- **Breaking changes**: + + - ``scala-scalastyle`` now expects a ``scalastyle`` executable in + ``exec-path`` [GH-763] + - Drop support for legacy Ruby YAML implementations prior to Ruby 1.9.3 in + ``ruby-yaml`` + - Remove racket syntax checker due to possible code execution [GH-786] + +- New syntax checkers: + + - JSON with Python’s built-in ``json`` module [GH-758] + - Rust with ``cargo rustc`` [GH-772] + +- New features: + + - Add ``flycheck-help-echo-function`` to customize the Help Echo of Flycheck + overlays [GH-730] + - Use symbolic error IDs in Pylint [GH-714] + - Add ``flycheck-pylint-use-symbolic-id`` to disable symbolic IDs for Pylint + [GH-714] + - Add ``flycheck-command-wrapper-function`` to wrap syntax checker commands + before execution [GH-629] [GH-752] + - Add ``flycheck-executable-find`` to customise how Flycheck searches + executables [GH-752] + - Add ``flycheck-hlint-args`` to pass additional arguments to hlint + [GH-713][GH-762] + - Add ``flycheck-go-build-tags`` and ``flycheck-go-install-deps`` to specify + tags and automatically install dependencies with ``go build`` [GH-674] + - Add :standard-input property to syntax checkers to read source from standard + input [GH-673] [GH-728] + - Add support for JSX modes to some Javascript checkers [GH-778] + +- Improvements: + + - Improve mode line display for buffers with only info messages [GH-733] + - Merge messages of all errors under cursor for Help Echo [GH-730] + - Align multi-line messages in error list [GH-732] [GH-731] + - Cache GHC output for faster syntax checking and better template haskell + support [GH-708] + - Fall back to ``rst`` if ``rst-sphinx`` is disabled [GH-745] [GH-746] + - New uniform fringe indicators [GH-750] + - Demote AsciiDoc deprecation warnings to ``info`` level + +- Bug fixes: + + - Fix error patterns of ``coq`` [GH-742] + - Support GFortran 5 [GH-751] + - Fix stack overflow when parsing hlint errors [GH-760] + - Fix error columns of jsonlint + +0.24 (Aug 15, 2015) +------------------- + +- **Breaking changes**: + + - Remove Elixir syntax checker due to code execution [GH-630] + - Drop support for Emacs 24.1 and 24.2 + +- New syntax checkers: + + - Javascript with ``jscs`` [GH-634] and ``standard`` [GH-644] + - Jade [GH-686] + - SQL with ``sqllint`` [GH-691] + - Groovy [GH-716] + - Haskell with ``stack ghc`` [GH-711] + +- New features: + + - The error list can now be filtered by error level by pressing f + - Add ``flycheck-error-list-minimum-level`` to restrict error levels displayed + in the error list [GH-698] [GH-701] + - Add ``flycheck-perl-include-path`` to set include directories for Perl + [GH-621] + - Add ``flycheck-rust-args`` to pass additional arguments to ``rustc`` + - Add ``flycheck-dmd-args`` to pass additional arguments to ``dmd`` [GH-655] + - Add ``flycheck-erlang-include-path`` [GH-668] and + ``flycheck-erlang-library-path`` [GH-696] for Erlang + - Add ``flycheck-verilator-include-path`` to set include directories for + Verilator [GH-684] + - Add ``flycheck-cppcheck-include-path`` to set include directories for + cppcheck [GH-687] + - Add support for Hlint configuration file [GH-682] + - Add Hlint options for ignore rules, language extensions and hint packages + [GH-682] + +- Improvements: + + - Show chained checkers in Help buffers for syntax checkers [GH-571] + - Map custom error levels to compilation mode levels [GH-700] + - ``flycheck-verify-setup`` now includes the manually selected checker if any + [GH-705] + - ``flycheck-select-checker`` now shows a verification buffer if the selected + checker cannot be used [GH-705] + - Add ``flycheck-verify-checker`` to check whether a specific syntax checker + can be used in a buffer [GH-705] + +- Bug fixes: + + - Fix offset of column numbers in ESLint [GH-640] + - Properly parse indentation errors from Python 2.7 [GH-635] + - Don’t choke if ``default-directory`` does not exist [GH-625] + - Fix error parsing for Puppet 4 + - Fix duplicate checkdoc errors on Emacs 25 + - Fix level of ``info`` messages in ``flycheck-compile`` [GH-669] + - Allow custom ``:verify`` functions for command checkers [GH-672] + - Fix error when ``flycheck-scalastylerc`` was set to a non-existing file + - Fix error column offsets in ``scala-scalastyle`` + - Do not use ``r-lintr`` in non-R buffers [GH-607] + - Enforce output format of ``flake8`` [GH-704] + - Parse error ids from luacheck 0.11 + - Fix patterns for Puppet environment names [GH-694] + - Properly locate configuration files from jshint and jscs [GH-703] + - Fix column offsets in eslint 1.0 [GH-718] + +0.23 (Apr 6, 2015) +------------------ + +- **Breaking changes**: + + - New manual in native Texinfo format, to achieve higher quality Info manuals + - Remove ``make`` syntax checker due to various issues [GH-572] [GH-573] + - Remove ``zsh`` support from ``sh-shellcheck``, since Shellcheck does not + support Zsh anymore + - Remove ``global-flycheck-mode`` from customization interface [GH-595] + +- New syntax checkers: + + - R with ``lintr`` [GH-512] + - Lua with ``luacheck`` [GH-591] [GH-609] + - SCSS with ``scss-lint`` [GH-582] [GH-598] + +- New features: + + - Add ``flycheck-disable-checker`` to disable a syntax checker in the current + buffer + - Add ``flycheck-global-modes`` to control in which modes + ``global-flycheck-mode`` turns on ``flycheck-mode`` + - Add ``pedantic`` and ``pedantic-errors`` options to Clang and GCC [GH-543] + - Add ``flycheck-foodcritic-tags`` to select tags for Foodcritic [GH-560] + +- Improvements: + + - ``chef-foodcritic`` handles relative paths correctly now [GH-556] + - Global Flycheck Mode enables Flycheck Mode even if there is no syntax + checker for the buffer yet [GH-568] + - ``handlebars`` now supports Web Mode [GH-605] + - Extract error IDs from ``rustc`` + - Don’t cache last syntax checker in buffer anymore + +- Bug fixes: + + - Fix void variable error when trying to use ``flycheck-compile`` with a + non-command checker [GH-563] + - Fix faulty mode line reporting [GH-564] + - Automatically initialize packages when checking ``user-init-file`` + - Properly initialize hook variables [GH-593] + - Fix handling of file names with symbolic links for some checkers [GH-561] + - Parse multiline type errors from ``rustc`` [GH-592] + +0.22 (Dec 23, 2014) +------------------- + +- **Breaking changes**: + + - Never allow use of disabled checkers anymore, even with + ``flycheck-select-checker`` + - Error parsers **must** set the ``:buffer`` and ``:checker`` slots of + ``flycheck-error`` now + - The internals of syntax checker definitions have changed again. **All + packages depending on Flycheck must be recompiled!** [GH-524] + - ``flycheck-error-list-refresh`` is not an interactive command anymore + - Replace ``flycheck-perlcritic-verbosity`` with + ``flycheck-perlcritic-severity`` + - Replace ``flycheck-copy-messages-as-kill`` with + ``flycheck-copy-errors-as-kill`` [GH-529] + - Remove ``flycheck-google-messages`` command + - Options and config file variables are not buffer-local anymore [GH-546] + +- New syntax checkers: + + - Python with ``py_compile`` [GH-484] + +- New features: + + - ``flycheck-ert.el`` library to write unit tests for Flycheck extensions + - Add ``flycheck-define-generic-checker`` to define syntax checkers over + arbitrary Emacs Lisp functions [GH-169] [GH-524] + - Add ``flycheck-define-command-checker`` as non-macro variant of + ``flycheck-define-checker`` [GH-524] + - Add support for IDs of errors [GH-529] + - Add special ``id`` sexp to parse error ids with ``:error-patterns`` [GH-529] + - Parse error IDs from Checkstyle XML [GH-259] + - ``flycheck-copy-errors-as-kill`` can put error ids into kill ring now + [GH-529] + - Parse error IDs from many error checkers [GH-259] + - Verify Flycheck setup in a buffer with ``flycheck-verify-setup`` [GH-338] + - Add options for arbitrary arguments to some syntax checkers [GH-542] + - Add ``flycheck-flake8-error-level-alist`` to customize error levels from + flake8 [GH-454] + +- Improvements: + + - Automatically disable syntax checkers that report too many errors [GH-476] + - Reduce filesystem access when parsing errors to improve parsing speed + - Add explicit ``load-path`` inheritance to ``flycheck-emacs-lisp-load-path``, + via new ``inherit`` value [GH-511] + - Parse help messages from ``rustc`` [GH-517] + - ``g`` in the error list checks the source buffer again [GH-532] + - ``haskell-ghc`` supports literate Haskell now [GH-535] + +- Bug fixes: + + - Properly parse notes in ``sh-shellcheck`` [GH-508] + - Fix shell quoting in ``flycheck-compile`` [GH-522] [GH-523] + - Fix faulty properties of customize options which broke ``customize-changed`` + and related functions + - Fix use deprecated option in ``coffee-coffeelint`` + - Fix error columns of ``python-pylint`` and ``tex-chktex`` [GH-536] + - Correctly compute error level of errors on included files in ``c/c++-clang`` + and ``c/c++-gcc`` [GH-451] + +0.21 (Oct 26, 2014) +------------------- + +- **Breaking changes**: + + - ``html-tidy`` is not enabled in Web Mode anymore [GH-464] + - ``d-dmd`` now requires DMD 2.066 or newer [GH-460] + - ``:next-checkers`` now requires the maximum permissible level instead of a + custom predicate [GH-472] + - Remove ``flycheck-error-list-highlight-at-point`` face and related + functionality [GH-490] + +- New syntax checkers: + + - Coq + - RPM spec files with ``rpmlint`` [GH-480] [GH-481] + +- New features: + + - Add ``null-device`` symbol for syntax checker commands + - Add ``flycheck-display-error-messages-unless-error-list`` for + ``flycheck-error-display-function`` + - Add ``flycheck-error-list-after-refresh-hook`` to run after the error list + refreshes + - Add ``flycheck-navigation-minimum-level`` to restrict error levels available + for navigation [GH-398] [GH-485] + - The error list can be sorted by message and syntax checker name now [GH-500] + - Add ``flycheck-error-list-checker-name`` face to customize the appearance of + the syntax checker name in the error list [GH-500] + - Add ``flycheck-shellcheck-excluded-warnings`` to exclude warnings from + ShellCheck reports [GH-499] + - Add ``flycheck-add-mode`` to add a new major mode to a syntax checker + [GH-506] + - Add ``flycheck-gcc-openmp`` to enable OpenMP for GCC in C/C++ [GH-507] + +- Improvements: + + - Improve GCC syntax checking by expanding templates [GH-459] + - ``d-dmd`` reports errors with columns now [GH-460] + - Remove Projectile-based config file search [GH-461] + - Do not change point when navigating in the error list [GH-487] + - ShellCheck warnings now include the corresponding warning code + +- Bug fixes: + + - Expand ``default-directory`` before using it, to handle abbreviated paths + gracefully [GH-434] + - Restore mouse support in the error list [GH-468] + - ``less`` now correctly resolves relative paths in ``data-uri`` [GH-471] + - ``go-errcheck`` now properly uses package names as syntax checker arguments + - ``c/c++-clang`` now handles empty error messages [GH-497] + +0.20 (Aug 12, 2014) +------------------- + +- **Breaking changes**: + + - The internal names of syntax checker properties changed. **All packages + depending on Flycheck must be recompiled!** + - ``flycheck-substitute-argument`` always returns a list now + - The special meaning of a trailing ``=`` in ``(option …)`` and ``(config-file + …)`` is removed. Both arguments must now explicitly specify ``concat`` to + prepend the option as string. + +- New syntax checkers: + + - C/C++ with GCC [GH-408] + - Scala with scalastyle [GH-425] + - Fortran with GFortran [GH-414] [GH-450] + - Ada with GNAT [GH-414] [GH-457] + +- New features: + + - Add ``flycheck-clang-no-exceptions`` and ``flycheck-gcc-no-exceptions`` to + flag exceptions as errors in C++ [GH-412] + - Add ``flycheck-rust-crate-root`` to resolve inter-crate references in + ``rust`` [GH-417] + - Add ``flycheck-clang-blocks`` to enable the block syntax in Clang [GH-420] + - ``read-flycheck-checker`` now accepts a default value + - Add ``flycheck-status-changed-functions`` to react on status changes + - Make the mode line lighter of Flycheck customizable with + ``flycheck-mode-line`` + - Add ``flycheck-rubylintrc`` to support configuration files for + ``ruby-rubylint`` [GH-424] + - Add ``flycheck-rust-crate-type`` to make the Crate type customizable + [GH-446] + - The mode line of the error list is now customizable with + ``flycheck-error-list-mode-line`` [GH-454] + - Pressing ``n`` or ``p`` in the error list now shows the error at point in a + separate window [GH-452] [GH-454] + - Pressing ``RET`` in the error list now jumps to the error at point [GH-454] + - The error list can now be sorted by error level by clicking on the + corresponding list header, or by pressing ``S`` with point on the column + text [GH-454] + - Error levels defined with ``flycheck-define-error-level`` can now have a + numeric severity used for sorting [GH-454] + +- Improvements: + + - Use proper temporary files in ``python-flake8`` [GH-421] + - Demote errors from ``package-initialize`` in the ``emacs-lisp`` checker + [GH-423] + - ``flycheck-select-checker`` now uses the last used syntax checker as default + when reading from minibuffer + - ``flycheck-compile`` now prompts for the syntax checker to run as + ``compile`` command [GH-428] + - The ``rust`` syntax checker shows info messages now [GH-439] + - The ``sass`` and ``scss`` syntax checkers now use a temporary directory for + their cache [GH-443] [GH-454] + - Change the default of ``flycheck-eslintrc`` to ``nil`` [GH-447] + - Show the menu on the mode line lighter [GH-365] + - Greatly improve Flycheck's menu + - ``n`` and ``p`` now navigate the error list by errors, not by lines + [GH-452][GH-444] + - ``c/c++-clang`` does not use in-place temporary files anymore [GH-456] + +- Bug fixes: + + - Properly support ``unload-feature`` now + +- Other changes: + + - Remove dependencies on f.el and s.el + +0.19 (Jun 12, 2014) +------------------- + +- Flycheck now has an official logo [GH-331] + +- **Breaking changes**: + + - The ``ruby-rubylint`` syntax checker now requires Ruby Lint 2.0 or + newer. [GH-405] + +- New syntax checkers: + + - Go with ``errcheck`` [GH-393] + +- New features: + + - Add ``flycheck-keymap-prefix`` to change the prefix key for Flycheck + keybindings [GH-381] + - Make the prefix of Flycheck's temporary files customizable with + ``flycheck-temp-prefix`` [GH-387] + - Add ``:error-filter`` property for syntax checkers to apply a custom + function to modify or filter errors after parsing [GH-397] + - Add ``flycheck-rust-check-tests`` to disable syntax checking of test code in + Rust [GH-406] + - Add ``flycheck-cppcheck-inconclusive`` to enable cppcheck tests that might + give false positives [GH-407] + +- Improvements: + + - Collapse redundant whitespace in messages from ``emacs-lisp`` [GH-397] + - Dedent messages from ``haskell-ghc`` [GH-397] + - Fold errors in included files into the error messages of the corresponding + include in ``c/c++-clang`` [GH-397] + - The ``ruby-rubylint`` syntax checker now supports ruby-lint 2.0 and newer + [GH-405] + +- Bug fixes: + + - When stopping Flycheck, correctly kill running processes and cleanup their + temporary files [GH-334] + - Do not choke on files without extensions in ``haskell-ghc`` + - Fix spurious warning when a syntax checker reports errors, but not for the + file being checked [GH-391] + - Do not signal errors in Go Mode, when ``go`` is not available + +0.18 (Mar 24, 2014) +------------------- + +- **Breaking changes**: + + - The POSIX script syntax checkers ``sh-bash`` and ``sh-dash`` were renamed to + ``sh-posix-bash`` and ``sh-posix-dash`` respectively. The ``bash`` and + ``zsh`` syntax checkers were renamed to ``sh-bash`` and ``sh-zsh`` + respectively. Thus, all shell script syntax checkers now live in the ``sh-`` + prefix. + - ``rst-sphinx`` requires Sphinx 1.2 or newer now. + - ``rustc`` requires Rust 0.10 (not yet released at the time of writing) or + newer now [GH-353] + +- New syntax checkers: + + - Perl with Perl Critic [GH-88] + - Replace GNU Make with POSIX Make [GH-322] + - Shellcheck [GH-267] + - Go with ``golint`` [GH-328] + - Go with ``go tool vet`` [GH-329] + +- New features: + + - Add ``flycheck-rust-library-path`` to specify library locations for ``rust`` + - Add ``flycheck-dmd-include-path`` to change the include path of ``d-dmd`` + [GH-344] + +- Improvements: + + - ``flycheck-parse-checkstyle`` supports ``info`` level messages now + - Correctly parse multiline error messages of ``go-build`` and ``go-test`` + - ``rst-sphinx`` supports custom nodes without explicit writer support now, by + using the ``pseudoxml`` builder. + - Avoid warnings about missing main functions in ``rust`` + - Properly resolve relative filenames in ``.. include::`` directives in + ``rst`` + - Use ``--unix_mode`` option in ``javascript-gjslint`` to get the file name + [GH-348] + - Puppet Lint messages now include the name of the corresponding check + - ``rustc`` supports upcoming Rust 0.10 now [GH-353] + - Flycheck now handles Clang errors from included files [GH-367] + +0.17 (Feb 1, 2014) +------------------ + +- The manual was ported to Sphinx_ and is now located at + http://flycheck.readthedocs.org [GH-274] + +- **Breaking changes**: + + - The default ``flycheck-completion-system`` was changed to nil, i.e. the + built-in ``completing-read``, for compliance with Emacs' defaults. To + restore the previous behaviour, add ``(eval-after-load 'flycheck '(setq + flycheck-completion-system 'ido))`` to your ``init.el``. + - ``flycheck-count-errors`` counts errors of all levels now, and returns an + alist mapping error symbols to error counts. + +- New syntax checkers: + + - RST (ReStructuredText) using Sphinx + - GNU Make [GH-321] + +- New features: + + - Extend syntax checkers with ``flycheck-add-next-checkers`` [GH-266] + +- Improvements: + + - Immediately re-check the buffer when it was changed during a syntax check + [GH-301] + - Do not defer syntax checker after idle change timeout [GH-305] + - Do not use the generic ``rst`` syntax checker in Sphinx projects + anymore, to avoid false positives by Sphinx-only markup + - Check for more than just syntax errors in ``rust`` [GH-314] + - ``chef-foodcritic`` supports ``enh-ruby-mode`` now + +- Bug fixes + + - Do not attach syntax checker processes to the buffer anymore + [GH-298] + - Do not visit the file to check in ``emacs-lisp`` and + ``emacs-lisp-checkdoc`` to avoid unintended side effects [GH-319] + +0.16 (Jan 11, 2014) +------------------- + +- **Breaking changes**: + + - Argument substitution is no longer performed on syntax checker + executables. The executable must be a string. + - Split out ``haskell-hdevtools`` into a separate package. See + flycheck-hdevtools_ [GH-275] + - Drop support for coffeelint 0.x + - The error list is reimplemented on top of Tabulated List Mode. This greatly + changes the appearance and behaviour of the error list [GH-230] + +- New syntax checkers: + + - Ruby with ``ruby-lint`` [GH-250] + - Handlebars [GH-270] + - YAML with ``yaml-jsyaml`` [GH-253] + - Chef recipes with ``foodcritic`` [GH-255] + - AsciiDoc [GH-276] + - CFEngine [GH-271] + - Racket [GH-277] + - Texinfo + - Verilog [GH-296] + - Javascript with ``eslint`` [GH-291] + - ERuby [GH-285] + +- New features: + + - Define variables to override the executables of syntax checkers [GH-272] + - Interactively set the executable of a syntax checker with + ``flycheck-set-checker-executable`` [GH-272] + - Disable syntax checkers easily with ``flycheck-disabled-checkers`` [GH-269] + - Add support for the Compass CSS framework in the ``sass`` and ``scss`` + checkers, with ``flycheck-sass-compass`` and ``flycheck-scss-compass`` + respectively [GH-268] + - Disable style checks in ``ruby-rubocop`` with ``flycheck-rubocop-lint-only`` + [GH-287] + - Add support for Microsoft extensions in ``c/c++-clang`` via + ``flycheck-clang-ms-extensions`` [GH-283] + - New faces ``flycheck-error-list-info``, ``flycheck-error-list-warning``, + ``flycheck-error-list-error``, ``flycheck-error-list-line-number`` and + ``flycheck-error-list-column-number`` [GH-230] + - Add ``flycheck-ghc-no-user-package-database`` to disable the user package + database for ``haskell-ghc`` + - Add ``flycheck-ghc-package-databases`` to add additional package databases + to ``haskell-ghc`` + - Add ``flycheck-ghc-search-path`` to add additional directories to the search + path of ``haskell-ghc`` + +- Improvements: + + - Demote Rubocop convention messages to ``info`` level + - Stop Flycheck before the buffer is reverted [GH-282] + - Properly resolve local module imports in ``haskell-ghc`` + +- Bug fixes: + + - Make relative imports work with ``python-pylint`` [GH-280] + - Fix parsing of errors in ``scss`` and ``sass`` + +.. _flycheck-hdevtools: https://github.com/flycheck/flycheck-hdevtools + +0.15 (Nov 15, 2013) +------------------- + +- Flycheck has a new home at https://github.com/flycheck/flycheck, the online + manual moved to http://flycheck.github.io. + +- **Breaking changes**: + + - Do not add the current directory to the ``emacs-lisp`` syntax checker load + path + - ``flycheck-list-errors`` cannot list errors at point anymore. It does not + accept a prefix argument anymore, and takes zero arguments now [GH-214] + - ``flycheck-display-errors-in-list`` is gone. The error list automatically + highlights the error at point now [GH-214] + - Remove obsolete ``flycheck-declare-checker`` + +- New syntax checkers: + + - YAML [GH-236] + - Javascript with ``gjslint`` [GH-245] + - Slim [GH-246] + - PHP using ``phpmd`` [GH-249] + +- New features: + + - Support IDO or Grizzl_ as completion systems for ``flycheck-select-checker`` + at ``C-c ! s`` + - Disable standard error navigation with + ``flycheck-standard-error-navigation`` [GH-202] + - Add ``flycheck-clang-language-standard`` to choose the language + standard for C/C++ syntax checking [GH-207] + - Add ``flycheck-clang-definitions`` to set additional definitions for C/C++ + syntax checking [GH-207] + - Add ``flycheck-clang-no-rtti`` to disable RTTI for C/C++ syntax checking + [GH-207] + - Add new option cell ``option-flag`` for boolean flags in syntax checker + commands + - Add ``flycheck-clang-includes`` to include additional files for C/C++ syntax + checking [GH-207] + - Add configuration file variable ``flycheck-pylintrc`` for Pylint + - New faces ``flycheck-error-list-highlight-at-point`` and + ``flycheck-error-list-highlight`` to highlight the errors at point and at + the current line respectively in the error list [GH-214] + - The error list now automatically updates to show the errors of the current + buffer [GH-214] + - Define new error levels with ``flycheck-define-error-level`` [GH-212] + - Add ``flycheck-clang-standard-library`` to choose the standard library for + C/C++ syntax checking [GH-234] + - Customize the delay for displaying errors via + ``flycheck-display-errors-delay`` [GH-243] + - Add ``info`` level for informational annotations by syntax checkers [GH-215] + - Add a new symbol ``temporary-file-name`` to pass temporary file names to + syntax checkers [GH-259] + +- Improvements: + + - The error list now refreshes automatically after each syntax check [GH-214] + - The errors at point are now automatically highlighted in the error list + [GH-214] + - ``emacs-lisp-checkdoc`` does not longer check ``.dir-locals.el`` files + - Do not automatically check syntax in encrypted files [GH-222] + - Parse notes from ``c/c++-clang`` into info level messages [GH-215] + - Parse convention warnings from ``pylint`` to info level [GH-204] + - Demote naming warnings from ``python-flake8`` to info level [GH-215] + - Support ``enh-ruby-mode`` in Ruby syntax checkers [GH-256] + - Parse columns from ``python-pylint`` errors + - Do not compress temporary files for syntax checks if the original file was + compressed + +- Bug fixes: + + - Find local includes in the Clang syntax checker [GH-225] + - Do not emit spurious flawed definition warning in the ``rst`` syntax checker + - Handle abbreviated file names in ``luac`` output, by simply ignoring them + [GH-251] + - Correctly redirect the output binary of the ``go-build`` syntax checker + [GH-259] + - Fix Cppcheck parsing with the built-in Emacs XML parser [GH-263] + +.. _Grizzl: https://github.com/grizzl/grizzl + +0.14.1 (Aug 16, 2013) +--------------------- + +- Bug fixes: + + - Add a missing dependency [GH-194] + +0.14 (Aug 15, 2013) +------------------- + +- **Breaking changes**: + + - Introduce ``flycheck-define-checker`` and obsolete + ``flycheck-declare-checker`` [GH-163] + - Remove the obsolete ``flycheck-error-face`` and ``flycheck-warning-face`` + - Do not initialize packages by default in ``emacs-lisp`` syntax checker for + non-configuration files [GH-176] + - Change the default ``flycheck-highlighting-mode`` to ``symbols`` [GH-179] + - Drop support for Pylint 0.x in ``python-pylint`` [GH-184] + +- New features: + + - List errors at point only with prefix arg to ``flycheck-list-errors`` + [GH-166] + - Add new display function ``flycheck-display-errors-in-list`` to display + errors at point in the error list [GH-166] + - New ``option-list`` argument cell to pass option lists to a syntax checker + - New ``flycheck-emacs-lisp-load-path`` option to customize the ``load-path`` + used by the ``emacs-lisp`` syntax checker [GH-174] + - New ``flycheck-emacs-lisp-initialize-packages`` option to initialize + packages in the ``emacs-lisp`` syntax checker [GH-176] + - New ``flycheck-emacs-lisp-package-user-dir`` option to configure the package + directory for the ``emacs-lisp`` syntax checker [GH-176] + - New option filter ``flycheck-option-comma-separated-list`` for options with + comma separated lists as values + - New highlighting mode ``symbols`` to highlight the symbol pointed to by an + error [GH-179] + +- New syntax checkers: + + - LESS [GH-160] + - Haskell with ``ghc``, ``hdevtools`` and ``hlint`` [GH-162] + - C/C++ with ``cppcheck`` [GH-170] + - C/C++ with ``clang`` [GH-172] + - CoffeeScript with ``coffee`` + - XML with ``xmllint`` [GH-180] + - D with ``dmd`` [GH-167] + +- Improvements: + + - Support Web Mode in ``html-tidy`` syntax checker [GH-157] + - Support Rubocop 0.9 and drop support for older Rubocop releases [GH-159] + - Include the message ID in error messages from ``python-pylint`` + +- Bug fixes: + + - Fix warnings about flawed definitions in ``emacs-lisp`` and + ``emacs-lisp-checkdoc``, caused by faulty formatting of sexps + - Refresh error lists when pressing ``g`` [GH-166] + - Do not obscure active minibuffer input when displaying errors in the echo + area [GH-175] + - Fix universal prefix argument for ``flycheck-next-error`` at ``C-c ! n`` + - Correctly parse output of ``coffeelint`` 0.5.7 [GH-192] + - Correctly parse output of ``pylint`` 1.0 [GH-184] + +0.13 (Jun 28, 2013) +------------------- + +- **Breaking changes**: + + - Obsolete ``flycheck-warning-face`` and ``flycheck-error-face`` in favor + ``flycheck-warning`` and ``flycheck-error`` respectively + - Obsolete ``:predicate`` forms in favor of ``:predicate`` functions + - ``flycheck-def-config-file-var`` does not automatically mark variables as + safe anymore + +- New features: + + - Make fringe indicator faces customizable independently with + ``flycheck-fringe-error`` and ``flycheck-fringe-warning`` + - Improve the default faces by using underlines instead of foreground colors, + if possible + - Customizable error processing with ``flycheck-process-error-functions`` + [GH-141] + - Make the delay before starting a syntax check customizable via + ``flycheck-idle-change-delay`` [GH-144] + - Make display of errors under point customizable via + ``flycheck-display-errors-function`` [GH-156] + +- Improvements + + - Always highlight errors on top of warnings now + - Do not trigger syntax checks in the middle of commands [GH-141] + - Add the current directory to load path in the ``emacs-lisp`` syntax checker + - Do not longer use the ``emacs-lisp-checkdoc`` syntax checker in Scratch + buffers + - Do not flush temporary files onto disk [GH-149] + - Syntax checkers may have error patterns and error parser now + - Predicate forms are now wrapped into functions and compiled into functions + during byte compilation + - Copy each message separately in ``flycheck-copy-messages-as-kill`` + - Mark some customizable variables as safe for file variable usage, most + notably ``flycheck-indication-mode``, ``flycheck-highlighting-mode`` and + ``flycheck-idle-change-delay``. + +- Bug fixes: + + - Fix error when searching for a configuration file outside a Projectile + project + - Do not start a syntax check before the ``flycheck-mode-hook`` was run + - Do not start automatic syntax checks if Flycheck Mode is disabled + - Defer the initial syntax check until after the current interactive command + [GH-143] + - Correctly clean up information about running processes + - Fix compatibility with Emacs 24.2 and earlier [GH-150] + - Fix version information on Emacs trunk builds + +0.12 (May 18, 2013) +------------------- + +- New syntax checkers: + + - Ruby using ``jruby`` [GH-136] + - Puppet [GH-138] + +- New features: + + - Highlight error expressions by default, with the new ``sexps`` highlighting + mode + - Automatically check syntax some time after the last change in the buffer + [GH-140] + - Add ``flycheck-version`` to determine the installed Flycheck version + - Add ``flycheck-list-errors``, mapped to ``C-c ! l``, to list all errors in a + separate buffer + +- Improvements: + + - Defer syntax checks while a buffer is reverted, to avoid race conditions + +- Bug fixes: + + - Correctly parse syntax errors from JRuby [GH-136] + +0.11 (May 01, 2013) +------------------- + +- New syntax checkers: + + - Scala [GH-124] + +- New features: + + - Customizable error indication with control of the fringe side, via + ``flycheck-indication-mode`` + - Customizable automatic syntax checking, via + ``flycheck-check-syntax-automatically`` [GH-128] + - Customizable configuration file search, via + ``flycheck-locate-config-file-functions`` [GH-133] + - Find configuration files in Projectile_ projects + - Add ``flycheck-before-syntax-check-hook`` and + ``flycheck-syntax-check-failed-hook`` + +- Improvements: + + - The ``ruby`` syntax checker now differentiates warnings from errors [GH-123] + - Faces are now in a separate customization group + +- Bug fixes: + + - Add missing customization group for syntax checker options + +.. _Projectile: https://github.com/bbatsov/projectile + +0.10 (Apr 21, 2013) +------------------- + +- Flycheck uses ``cl-lib`` now. This library is built-in as of GNU Emacs + 24.3. For earlier releases of GNU Emacs 24 an additional compatibility library + will be installed from GNU ELPA. + +- New syntax checkers: + + - POSIX Shell script using ``bash`` [GH-112] + - Ruby using ``rubocop`` [GH-113] + - Elixir [GH-108] + - Erlang [GH-122] + +- Removed syntax checkers: + + - Python using Pyflakes. Use the superior Flake8 syntax checker [GH-115] + +- New features: + + - Add ``flycheck-copy-messages-as-kill``, mapped to ``C-c ! C-w``, to copy all + error messages under point into kill ring + - Add ``flycheck-google-messages``, mapped to ``C-c ! /``, to google for error + messages under point. Needs the `Google This`_ library + - Syntax checkers can redirect output to a temporary directory now using the + ``temporary-directory`` argument symbol + +- Improvements: + + - Call option filters for ``nil`` values, too + - Improve error parsing in Bash syntax checker [GH-112] + - Error navigation does not cross restrictions in narrowed buffers anymore + - Try to preserve the non-directory part of the buffer's file name when + substituting the ``source`` symbol [GH-99] + +- Bug fixes: + + - Fix error highlighting and navigation in narrowed buffers + - Use a hopefully more reliable way to parse output of PHP + CodeSniffer [GH-118] + +.. _Google This: https://github.com/Malabarba/emacs-google-this + +0.9 (Apr 13, 2013) +------------------ + +- New syntax checkers: + + - SCSS using ``scss`` [GH-103] + - RST (ReStructuredText) using Docutils + - Go using ``go build`` and ``go test`` [GH-107] + +- Improvements: + + - Quit the error message window when navigating away from error locations + +0.8 (Apr 9, 2013) +----------------- + +- New syntax checkers: + + - Go using ``gofmt`` [GH-91] + - Rust using ``rustc`` [GH-101] + +- New features: + + - Add a global Flycheck mode. ``(global-flycheck-mode)`` is now the + recommended way to enable Flycheck [GH-29] + - Add support for syntax checker options [GH-72] + - Add option for the coding standard used by the ``php-phpcs`` syntax checker + - Add options for the maximum McCabe complexity and the maximum line length to + ``python-flake8`` + +- Improvements: + + - Support McCabe warnings in ``python-flake8`` + - Support warnings from ``flake8`` 2 + - Show long error messages in a popup buffer [GH-94] + - Show all error messages at point [GH-96] + - Add support for naming warings from ``flake8`` 2 [GH-98] + - Flycheck mode is not longer enabled for buffers whose names start with a + space + - Improve highlighting to reduce screen flickering [GH-100] + +0.7.1 (Feb 23, 2013) +-------------------- + +- Bug fixes: + + - Do not signal errors from ``flycheck-mode`` [GH-87] + - Correctly fall back to ``$HOME`` when searching configuration files + - Correctly ascend to parent directory when searching configuration files + +- API changes: + + - Rename ``config`` cell to ``config-file`` + - Allow to pass the result of ``config-file`` cells as single argument + - Add support for evaluating Lisp forms in syntax checker commands [GH-86] + +0.7 (Feb 14, 2013) +------------------ + +- New features: + + - Navigate to source of syntax checker declarations from syntax checker help + - Add online Info manual [GH-60] + +- Improvements: + + - Use pipes instead of TTYs to read output from syntax checkers + - Defer syntax checks for invisible buffers [GH-80] + - Immediately display error messages after error navigation [GH-62] + +- Bug fixes: + + - Never select deleted buffers + - Do not let the debugger interfere with necessary cleanup actions + - Do not attempt to parse empty XML trees [GH-78] + - Fix infinite recursion on Windows [GH-81] + +0.6.1 (Jan 30, 2013) +-------------------- + +- Fix package dependencies + +0.6 (Jan 29, 2013) +------------------ + +- New syntax checkers: + + - Emacs Lisp with ``checkdoc-current-buffer`` [GH-53] + - PHP with PHP CodeSniffer [GH-72] + +- Removed syntax checkers: + + - Javascript with ``jsl`` + +- New features: + + - Error navigation with ``next-error`` and ``previous-error`` [GH-26] + - Fringe icons instead of error indicators [GH-33] + - Menu entry for Flycheck [GH-59] + - Customizable error highlighting, taking the column number into account + [GH-35] + - Configuration files for syntax checkers + - Add configuration file support to the syntax checkers ``coffee-coffeelint``, + ``html-tidy``, ``javascript-jshint``, ``pyton-flake8`` and ``tex-chktex`` + - Allow to compile a buffer with a syntax checker for testing purposes [GH-58] + - Use multiple syntax checkers during a syntax check [GH-31] + - Add dedicated help for syntax checkers [GH-52] + +- Improvements: + + - Match error patterns in order of declaration [GH-55] + +- Bug fixes: + + - Inherit highlighting faces from built-in faces [GH-24] + - Correct error patterns of the HTML syntax checker [GH-36] + - Detect syntax errors in the ``python-flake8`` syntax checker + [GH-42] + - Fix various regressions after introducing unit tests + - Inhibit syntax checking during package installation [GH-45] + - Disable syntax checking in Tramp buffers [GH-54] + - Preserve whitespace in error messages [GH-65] + +- API changes: + + - Replace syntax checker variables with syntax checker declarations [GH-41] + - Support parsing errors with arbitrary functions instead of error patterns + [GH-38] + - Add an error parser for Checkstyle-like XML output [GH-38] + +0.5 (Dec 28, 2012) +------------------ + +- New syntax checkers: + + - SASS [GH-15] + - Perl [GH-21] + - XML + - Lua [GH-30] + +- New features: + + - Support manual buffer-local selection of syntax checker [GH-25] + - Add customizable error indicators [GH-28] + - Echo error messages at point without 3rd-party libraries like + flymake-cursor_ [GH-27] + +- Improvements: + + - Remember the last automatically selected syntax checker [GH-24] + +- Bug fixes: + + - Fix syntax checking of buffers without backing files [GH-19] + +- API changes: + + - Replace underlying Flymake API with a custom syntax checking implementation + [GH-15] + +.. _flymake-cursor: https://www.emacswiki.org/emacs/FlymakeCursor + +0.4 (Nov 21, 2012) +------------------ + +- Rename the project to Flycheck [GH-5] +- New syntax checkers + + - HAML [GH-9] + - CSS [GH-9] + - Javascript with ``jsl`` [GH-9] + - Javascript with ``jshint`` [GH-16] + - JSON [GH-12] + - LaTeX with ``lacheck`` + +- Bug fixes: + + - Fix type error when checking compressed Emacs Lisp [GH-10] + +0.3 (Nov 21, 2012) +------------------ + +- Replace ``flymake-mode`` with a custom syntax checking minor mode [GH-4] + +0.2 (Oct 25, 2012) +------------------ + +- New syntax checkers: + + - PHP + +- API changes: + + - Simplify syntax checker declarations [GH-2] + +0.1 (Oct 11, 2012) +------------------ + +Initial release as flymake-checkers + +- New syntax checkers: + + - TeX/LaTeX + - Shell scripts + - Python + - Ruby + - Coffeescript + - Emacs Lisp diff --git a/CHANGES.rst b/CHANGES.rst new file mode 100644 index 0000000..48aeb30 --- /dev/null +++ b/CHANGES.rst @@ -0,0 +1,412 @@ +33-cvs (in development) +======================= + +- New features and improvements + + - The ``flycheck-verify-setup`` UI now includes buttons to re-enable manually + disabled checkers and to try to re-enable automatically disabled checkers + (command checkers are automatically disabled when their executable cannot be + found). [GH-1755] + - Error explainers can now return URLs (to show a webpage) or functions (to + use custom formatting). For example, the Rust checker now renders + explanations using ``markdown-view-mode``. [GH-1753] + +- **Breaking changes** + + - The variable ``flycheck-current-errors`` now contains errors in the order in + which they were returned by checkers. In previous versions of Flycheck, + this list was sorted by error position and severity. [GH-1749] + +32-cvs (frozen on May 3rd, 2020) +================================ + +- Highlights + + - Many checkers and compiler, such as ``ocaml``, ``rust``, ``eslint``, and + others, include end-line and end-column information. Flycheck can now + highlight the exact region that they report. Authors of checker definitions + can use the new ``:end-line`` and ``:end-column`` arguments in + ``flycheck-error-new``, or the new ``end-line`` and ``end-column`` fields in + error patterns. [GH-1400] + + - Errors that checkers return for other files will now be displayed on the + first line of the current buffer instead of begin discarded. The error list + indicates which file each error came from, and navigation moves + automatically moves between files. This change helps with compiled + languages, where an error in another file may cause the current file to be + considered invalid. Variables ``flycheck-relevant-error-other-file-show`` + and ``flycheck-relevant-error-other-file-minimum-level`` control this + behavior. [GH-1427] + + - Flycheck can now draw error indicators in margins in addition to fringes. + Margins can contain arbitrary characters and images, not just monochrome + bitmaps, allowing for a better experience on high-DPI screens. + ``flycheck-indication-mode`` controls this behavior, and + ``flycheck-set-indication-mode`` can be used to automatically adjust the + fringes and margins. Additionally, Flycheck's will now use high-resolution + fringe bitmaps if the fringe is wide enough [GH-1742, GH-1744] + + - Error highlighting is now configurable, using the new + ``flycheck-highlighting-style`` variable: instead of applying + level-dependent faces (typically with wavy underlines), Flycheck can now + insert delimiters around errors, or mix styles depending on how many lines + an error covers. Additionally, stipples are added in the fringes to + indicate errors that span multiple lines. [GH-1743] + +- New features and improvements + + - Flycheck can now trigger a syntax check automatically after switching + buffers, using the ``idle-buffer-switch`` option in + ``flycheck-check-syntax-automatically``. This is useful when errors in a + file are due to problems in a separate file. Variables + ``flycheck-idle-buffer-switch-delay`` and + ``flycheck-buffer-switch-check-intermediate-buffers`` control the + functionality. [GH-1297] + - Flycheck will now use Emacs' native XML parsing when libXML fails. This + behavior can be changed by customizing ``flycheck-xml-parser``. [GH-1349] + - ``flycheck-verify-setup`` now shows more clearly which checkers + will run in the buffer, and which are misconfigured. [GH-1478] + - Flycheck now locates checker executables using a customizable function, + ``flycheck-executable-find``. The default value of this function allows + relative paths (set e.g. in file or dir-local variables) in addition to + absolute paths and executable names. [GH-1485] + - Checkers that report error positions as a single offset from the start of + the file can use the new ``flycheck-error-new-at-pos`` constructor instead + of converting that position to a line and a column. [GH-1400] + - Config-file variables can now be set to a list of file names. This is + useful for checkers like mypy which don't run correctly when called from a + subdirectory without passing an explicit config file. [GH-1711] + - Thanks to algorithmic improvements in error reporting, Flycheck is now much + faster in large buffers. [GH-1750] + +- New syntax checkers: + + - Awk with ``gawk`` [GH-1708] + - Bazel with ``bazel-buildifier`` [GH-1613] + - CUDA with ``cuda-nvcc`` [GH-1508] + - CWL with ``schema-salad-tool`` [GH-1361] + - Elixir with ``credo`` [GH-1062] + - JSON with ``json-jq`` [GH-1568] + - Jsonnet with ``jsonnet`` [GH-1345] + - MarkdownLint CLI with ``markdownlint`` [GH-1366] + - mypy with ``python-mypy`` [GH-1354] + - Nix with ``nix-linter`` [GH-1530] + - Opam with ``opam lint`` [GH-1532] + - protobuf-prototool with ``prototool`` [GH-1591] + - Rust with ``rust-clippy`` [GH-1385] + - Ruumba with ``eruby-ruumba`` [GH-1616] + - Staticcheck with ``go-staticheck`` [GH-1541] + - terraform with ``terraform fmt``, ``tflint`` [GH-1586] + - Tcl with ``nagelfar`` [GH-1365] + - Text prose with ``textlint`` [GH-1534] + - VHDL with ``ghdl`` [GH-1160] + +- Checker improvements: + + - ``python-pylint`` and ``python-flake8`` are now invoked with ``python -c``, + to make it easier to change between Python 2 and Python 3. [GH-1113] + - Add ``flycheck-perl-module-list`` to use specified modules when + syntax checking code with the ``perl`` checker. [GH-1207] + - ``rust-cargo`` now uses ``cargo check`` and ``cargo test``. [GH-1289] + - Add ``flycheck-ghc-stack-project-file`` for the + ``haskell-stack-ghc`` checker. [GH-1316] + - Add ``flycheck-cppcheck-suppressions-file`` to pass a suppressions + file to cppcheck. [GH-1329] + - Add ``--force-exclusion`` flag to ``rubocop`` command. [GH-1348] + - Flycheck now uses ESLint's JSON output instead of checkstyle XML. [GH-1350] + - Add ``flychjeck-eslint-args`` to pass arguments to ``javascript-eslint``. + [GH-1360] + - Flycheck will now execute ``rubocop`` from the directory where a ``Gemfile`` + is located. If a ``Gemfile`` does not exist, the old behaviour of running + the command from the directory where ``.rubocop.yml`` is found will be + used. [GH-1368] + - Add ``flycheck-sh-bash-args`` to pass arguments to ``sh-bash``. [GH-1439] + - ``haskell-stack-ghc`` will not try to install GHC anymore. [GH-1443] + - Add ``flycheck-ghdl-ieee-library`` to select which standard IEEE + library to use for ghdl. [GH-1547] + - The ``javascript-eslint`` checker now supports ``typescript-mode`` by + default. + - Add ``flycheck-erlang-rebar3-profile`` to select which profile to + use when compiling erlang with rebar3. [GH-1560] + - Add ``flycheck-relevant-error-other-file-show`` to avoid showing errors + from other files. [GH-1579] + - The ``nix-linter`` checker now has an error explainer. [GH-1586] + - The Emacs Lisp checker can now run in buffers not backed by files. [GH-1695] + +- **Breaking changes** + + - Remove the ``javascript-jscs`` checker. [GH-1024] + - Remove the ``elixir-dogma`` checker. [GH-1450] + - ``rust-cargo`` now requires Rust 1.17 or newer. [GH-1289] + - ``rust`` now requires 1.18 or newer. [GH-1501] + - Rename ``flycheck-cargo-rustc-args`` to ``flycheck-cargo-check-args``. + [GH-1289] + - ``rust-cargo`` does not use the variable ``flycheck-rust-args`` anymore. + [GH-1289] + - Improve detection of default directory for ``haskell-ghc`` to consider + ``hpack`` project files. [GH-1435] + - Replace ``go tool vet`` with ``go vet``. [GH-1548] + - Remove the deprecated ``go-megacheck`` checker, which is replaced by + ``go-staticcheck``. [GH-1583] + +31 (Oct 07, 2017) +================= + +- **Breaking changes** + + - ``rust-cargo`` now requires Rust 1.15 or newer [GH-1201] + - Remove javascript-gjslint checker + +- New syntax checkers: + + - Protobuf with ``protoc`` [GH-1125] + - systemd-analyze with ``systemd-analyze`` [GH-1135] + - Nix with ``nix-instantiate`` [GH-1164] + - Dockerfile with ``hadolint`` [GH-1194] + - AsciiDoc with ``asciidoctor`` [GH-1167] + - CSS/SCSS/LESS with ``stylelint`` [GH-903] + - Ruby with ``reek`` [GH-1244] + - Go with ``megacheck`` [GH-1290] + - LLVM IR with ``llc`` [GH-1302] + - Text prose with ``proselint`` [GH-1304] + +- New features: + + - Add ``flycheck-xml-xmlstarlet-xsd-path`` and ``flycheck-xml-xmllint-xsd-path`` to + specify an XSD schema to validate XML documents against [GH-1272] + - Add ``flycheck-tslint-args`` to pass additional arguments to tslint [GH-1186] + - Add an error explainer to the ``rpm-rpmlint`` checker using + ``rpmlint -I`` [GH-1235] + - Add ``flycheck-emacs-lisp-check-declare`` to check function declaration in + the ``emacs-lisp`` checker [GH-1286] + - Add ``flycheck-shellcheck-follow-sources`` to check included files when + using the ``sh-shellcheck`` checker [GH-1256] + +- Improvements: + + - Use option ``flycheck-go-build-tags`` for ``go-test``, + ``go-vet`` and ``go-errcheck`` as well. + - Add a revert function to ``flycheck-verify-setup``, so hitting + ``g`` reloads the buffer. + - Make sure the erlang compiler is only run on compilable files. + - ``flycheck-tslint`` does not crash any more on deprecation notices [GH-1174] + - ``rust-cargo`` now checks integration tests, examples and benchmarks + [GH-1206] + - ``rust-cargo`` does not use ``flycheck-rust-library-path`` anymore, as + dependencies are taken care of by Cargo [GH-1206] + - ``c/c++-gcc`` checker now works from GCC 4.4 and up [GH-1226] + +30 (Oct 12, 2016) +================= + +- **Breaking changes** + + - Flycheck now requires flake8 3.0 or newer + - Remove ``--config`` option in ``lua-luacheck`` in favour of ``luacheck``'s + own ``.luacheckrc`` detection. Therefore ``flycheck-luacheckrc`` is + no longer used [GH-1057] + - ``:modes`` is now mandatory for syntax checker definitions [GH-1071] + - Remove jade checker [GH-951] [GH-1084] + - Remove ``javascript-eslintrc`` and instead rely on eslint's own configuration file + search [GH-1085] + - ``C-c ! e`` explains errors now [GH-1122] + +- New syntax checkers: + + - Elixir with ``dogma`` [GH-969] + - sass and scss with ``sass-lint`` [GH-1070] + - Pug [GH-951] [GH-1084] + +- New features: + + - Add ``flycheck-cargo-rustc-args`` to pass multiple arguments to cargo rustc + subcommand [GH-1079] + - Add ``:error-explainer`` to ``flycheck-define-checker`` and + ``flycheck-explain-error-at-point`` to display explanations of errors + [GH-1122] + - Add an error explainer to the ``rust`` and ``rust-cargo`` checkers using + ``rustc --explain`` [GH-1122] + - Add ``:enabled`` property to ``flycheck-define-checker`` [GH-1089] + +- Improvements: + + - Do not use ``javascript-eslint`` if eslint cannot find a valid configuration + [GH-1085] + - Automatically disable syntax checkers which are not installed instead of + checking executable before each syntax check [GH-1116] + - Add patterns for syntax errors to ``scheme-chicken`` [GH-1123] + +29 (Aug 28, 2016) +================= + +- **Breaking changes** + + - Change ``flycheck-eslint-rulesdir`` (string) to + ``flycheck-eslint-rules-directories`` (list of strings) [GH-1016] + - Require rust 1.7 or newer for ``rust`` and ``rust-cargo`` [GH-1036] + +- New syntax checkers: + + - Slim with ``slim-lint`` [GH-1013] + - CHICKEN Scheme with ``csc`` [GH-987] + +- New features: + + - Add ``:working-directory`` option to ``flycheck-define-command-checker`` + [GH-973] [GH-1012] + - ``flycheck-go-build-install-deps`` turns on dependency installation for ``go test`` + as well as ``go build`` [GH-1003] + +- Improvements: + + - Add default directory for ``haskell-stack-ghc`` and ``haskell-ghc`` checkers + [GH-1007] + - ``rust`` and ``rust-cargo`` checkers now support the new error format of + rust 1.12 [GH-1016] + - ``flycheck-verify-checker`` and ``flycheck-verify-setup`` now include + information about configuration files of syntax checkers [GH-1021] [GH-1038] + +28 (Jun 05, 2016) +================= + +- **Breaking changes**: + + - Rename ``luacheck`` to ``lua-luacheck`` to comply with our naming + conventions + - Remove ``flycheck-cppcheck-language-standard`` in favour of + ``flycheck-cppcheck-standards`` which is a list of standards [GH-960] + +- New features: + + - Add option to set binary name for ``rust-cargo`` [GH-958] + - Add ``flycheck-cppcheck-standards`` to pass multiple code standards to + cppcheck [GH-960] + - Add ``flycheck-cppcheck-suppressions`` to suppress warnings for cppcheck + [GH-960] + +- Improvements: + + - Check Racket syntax in Geiser Mode [GH-979] + +- Bug fixes + + - Do not signal errors when tslint reports no output [GH-981] + - Do not generate invalid temporary filenames on Windows [GH-983] + +27 (May 08, 2016) +================= + +- **Breaking changes** + + - Require PHP Code Sniffer 2.6 or newer for ``php-phpcs`` [GH-921] + +- New syntax checkers: + + - Go with ``go-unconvert`` [GH-905] + - Markdown with ``mdl`` [GH-839] [GH-916] + - TypeScript with ``tslint`` [GH-947] [GH-949] + +- Improvements: + + - Pass checkdoc settings from Emacs to `emacs-lisp-checkdoc` [GH-741] [GH-937] + +- Bug fixes: + + - Fix parsing of syntax errors in triple-quoted strings for + ``python-pycompile`` [GH-948] + - Correctly handle rules based on the current file name in ``php-phpcs`` + [GH-921] + +26 (Apr 27, 2016) +================= + +Flycheck now has a `Code of Conduct`_ which defines the acceptable behaviour and +the moderation guidelines for the Flycheck community. [GH-819] + +Flycheck also provides a `Gitter channel`_ now for questions and discussions +about development. [GH-820] + +The native Texinfo manual is again replaced with a Sphinx_ based documentation. +We hope that this change makes the manual easier to edit and to maintain and +more welcoming for new contributors. The downside is that we can not longer +include a Info manual in Flycheck’s MELPA packages. + +From this release onward Flycheck will use a single continuously increasing +version number. Breaking changes may occur at any point. + +.. _Code of Conduct: http://www.flycheck.org/en/latest/community/conduct.html +.. _Gitter channel: https://gitter.im/flycheck/flycheck +.. _Sphinx: http://sphinx-doc.org + +- **Breaking changes**: + + - Remove ``flycheck-copy-messages-as-kill``, obsolete since Flycheck + 0.22 + - Remove ``flycheck-perlcritic-verbosity``, obsolete since Flycheck + 0.22 + - Replace ``flycheck-completion-system`` with + ``flycheck-completing-read-function`` [GH-870] + - JSON syntax checkers now require ``json-mode`` and do not check in + Javascript Mode anymore + - Prefer eslint over jshint for Javascript + - Obsolete ``flycheck-info`` in favour of the new ``flycheck-manual`` command + +- New syntax checkers: + + - Processing [GH-793] [GH-812] + - Racket [GH-799] [GH-873] + +- New features: + + - Add ``flycheck-puppet-lint-rc`` to customise the location of the + puppetlint configuration file [GH-846] + - Add ``flycheck-puppet-lint-disabled-checks`` to disable specific + checks of puppetlint [GH-824] + - New library ``flycheck-buttercup`` to support writing Buttercup_ specs for + Flycheck + - Add ``flycheck-perlcriticrc`` to set a configuration file for + Perl::Critic [GH-851] + - Add ``flycheck-jshint-extract-javascript`` to extract Javascript + from HTML [GH-825] + - Add ``flycheck-cppcheck-language-standard`` to set the language + standard for cppcheck [GH-862] + - Add ``flycheck-mode-line-prefix`` to customise the prefix of + Flycheck’s mode line lighter [GH-879] [GH-880] + - Add ``flycheck-go-vet-shadow`` to check for shadowed variables + with ``go vet`` [GH-765] [GH-897] + - Add ``flycheck-ghc-stack-use-nix`` to enable Nix support for Stack GHC + [GH-913] + +- Improvements: + + - Map error IDs from flake8-pep257 to Flycheck error levels + - Explicitly display errors at point with ``C-c ! h`` [GH-834] + - Merge message and checker columns in the error list to remove redundant + ellipsis [GH-828] + - Indicate disabled checkers in verification buffers [GH-749] + - Do not enable Flycheck Mode in ``fundamental-mode`` buffers [GH-883] + - Write ``go test`` output to a temporary files [GH-887] + - Check whether ``lintr`` is actually installed [GH-911] + +- Bug fixes: + + - Fix folding of C/C++ errors from included files [GH-783] + - Fix verification of SCSS-Lint checkstyle reporter + - Don’t fall back to ``rust`` if ``rust-cargo`` should be used [GH-817] + - Don’t change current buffer when closing the error message buffer [GH-648] + - Never display error message buffer in current window [GH-822] + - Work around a caching issue in Rubocop [GH-844] + - Fix checkdoc failure with some Emacs Lisp syntax [GH-833] [GH-845] [GH-898] + - Correctly parse Haskell module name with exports right after the module name + [GH-848] + - Don’t hang when sending buffers to node.js processes on Windows + [GH-794][GH-850] + - Parse suggestions from ``hlint`` [GH-874] + - Go errcheck handles multiple ``$GOPATH`` entries correctly now + [GH-580][GH-906] + - Properly handle Go build failing in a directory with multiple packages + [GH-676] [GH-904] + - Make cppcheck recognise C++ header files [GH-909] + - Don’t run phpcs on empty buffers [GH-907] + +.. _Buttercup: https://github.com/jorgenschaefer/emacs-buttercup diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Cask b/Cask new file mode 100644 index 0000000..57510bd --- /dev/null +++ b/Cask @@ -0,0 +1,59 @@ +(source gnu) +(source melpa) + +(package-file "flycheck.el") + +(files "flycheck.el" "flycheck-ert.el" "flycheck-buttercup.el") + +(development + (depends-on "f") ; For some maintenance tools + (depends-on "buttercup") ; BDD test framework for Emacs + (depends-on "shut-up") ; Silence Emacs + + ;; Various modes for use in the unit tests + (depends-on "adoc-mode") + (depends-on "bazel-mode") + (depends-on "coffee-mode") + (depends-on "cperl-mode") + (depends-on "cwl-mode") + (depends-on "d-mode") + (depends-on "dockerfile-mode") + (depends-on "elixir-mode") + (depends-on "erlang") + (depends-on "ess") + (depends-on "geiser") + (depends-on "go-mode") + (depends-on "groovy-mode") + (depends-on "haml-mode") + (depends-on "handlebars-mode") + (depends-on "haskell-mode") + (depends-on "js2-mode") + (depends-on "js3-mode") + (depends-on "rjsx-mode") + (depends-on "json-mode") + (depends-on "julia-mode") + (depends-on "less-css-mode") + (depends-on "lua-mode") + (depends-on "markdown-mode") + (depends-on "mmm-mode") + (depends-on "nix-mode") + (depends-on "php-mode") + (depends-on "processing-mode") + (depends-on "protobuf-mode") + (depends-on "pug-mode") + (depends-on "puppet-mode") + ;; (depends-on "racket-mode") ;; https://github.com/greghendershott/racket-mode/issues/461 + (depends-on "rhtml-mode") + (depends-on "rpm-spec-mode") + (depends-on "rust-mode") + (depends-on "sass-mode") + (depends-on "scala-mode") + (depends-on "scss-mode") + (depends-on "slim-mode") + (depends-on "systemd") + (depends-on "terraform-mode") + (depends-on "tuareg") + (depends-on "typescript-mode") + (depends-on "web-mode") + (depends-on "yaml-mode") + ) diff --git a/Cask.24 b/Cask.24 new file mode 100644 index 0000000..dde8679 --- /dev/null +++ b/Cask.24 @@ -0,0 +1,59 @@ +(source gnu) +(source melpa) + +(package-file "flycheck.el") + +(files "flycheck.el" "flycheck-ert.el" "flycheck-buttercup.el") + +(development + (depends-on "f") ; For some maintenance tools + (depends-on "buttercup") ; BDD test framework for Emacs + (depends-on "shut-up") ; Silence Emacs + + ;; Various modes for use in the unit tests + (depends-on "adoc-mode") + ;; (depends-on "bazel-mode") ; requires Emacs 26+ + (depends-on "coffee-mode") + (depends-on "cperl-mode") + (depends-on "cwl-mode") + ;; (depends-on "d-mode") ; requires Emacs 25.1+ + (depends-on "dockerfile-mode") + (depends-on "erlang") + ;; Latest ess requires `project' from Emacs 25+. + ;; (depends-on "ess") + (depends-on "geiser") + (depends-on "go-mode") + (depends-on "groovy-mode") + (depends-on "haml-mode") + (depends-on "handlebars-mode") + ;; (depends-on "haskell-mode") ; requires Emacs 25.1+ + (depends-on "js2-mode") + (depends-on "js3-mode") + (depends-on "rjsx-mode") + (depends-on "json-mode") + (depends-on "julia-mode") + (depends-on "less-css-mode") + (depends-on "lua-mode") + ;; (depends-on "markdown-mode") ; 25+ + (depends-on "mmm-mode") + ;; (depends-on "nix-mode") ; 25+ + (depends-on "php-mode") + (depends-on "processing-mode") + (depends-on "protobuf-mode") + (depends-on "pug-mode") + (depends-on "puppet-mode") + ;; (depends-on "racket-mode") ; requires Emacs 25.1+ + (depends-on "rhtml-mode") + (depends-on "rpm-spec-mode") + ;; (depends-on "rust-mode") ; 25+ + (depends-on "sass-mode") + (depends-on "scala-mode") + (depends-on "scss-mode") + (depends-on "slim-mode") + (depends-on "systemd") + (depends-on "terraform-mode") + (depends-on "tuareg") + (depends-on "typescript-mode") + (depends-on "web-mode") + (depends-on "yaml-mode") + ) diff --git a/Cask.25 b/Cask.25 new file mode 100644 index 0000000..31b78c0 --- /dev/null +++ b/Cask.25 @@ -0,0 +1,58 @@ +(source gnu) +(source melpa) + +(package-file "flycheck.el") + +(files "flycheck.el" "flycheck-ert.el" "flycheck-buttercup.el") + +(development + (depends-on "f") ; For some maintenance tools + (depends-on "buttercup") ; BDD test framework for Emacs + (depends-on "shut-up") ; Silence Emacs + + ;; Various modes for use in the unit tests + (depends-on "adoc-mode") + ;; (depends-on "bazel-mode") ; requires Emacs 26+ + (depends-on "coffee-mode") + (depends-on "cperl-mode") + (depends-on "cwl-mode") + (depends-on "d-mode") + (depends-on "dockerfile-mode") + (depends-on "erlang") + (depends-on "ess") + (depends-on "geiser") + (depends-on "go-mode") + (depends-on "groovy-mode") + (depends-on "haml-mode") + (depends-on "handlebars-mode") + (depends-on "haskell-mode") + (depends-on "js2-mode") + (depends-on "js3-mode") + (depends-on "rjsx-mode") + (depends-on "json-mode") + (depends-on "julia-mode") + (depends-on "less-css-mode") + (depends-on "lua-mode") + (depends-on "markdown-mode") + (depends-on "mmm-mode") + (depends-on "nix-mode") + (depends-on "php-mode") + (depends-on "processing-mode") + (depends-on "protobuf-mode") + (depends-on "pug-mode") + (depends-on "puppet-mode") + ;; (depends-on "racket-mode") ;; https://github.com/greghendershott/racket-mode/issues/461 + (depends-on "rhtml-mode") + (depends-on "rpm-spec-mode") + (depends-on "rust-mode") + (depends-on "sass-mode") + (depends-on "scala-mode") + (depends-on "scss-mode") + (depends-on "slim-mode") + (depends-on "systemd") + (depends-on "terraform-mode") + (depends-on "tuareg") + (depends-on "typescript-mode") + (depends-on "web-mode") + (depends-on "yaml-mode") + ) diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000..bda2378 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,2 @@ +Clément Pit-Claudel (@cpitclaudel) +fmdkdd (@fmdkdd) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..066b941 --- /dev/null +++ b/Makefile @@ -0,0 +1,164 @@ +# Copyright (c) 2018 Flycheck contributors +# Copyright (c) 2012-2016 Sebastian Wiesner and Flycheck contributors + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# Programs +CASK = cask +EMACS = emacs +GIT = git +INKSCAPE = inkscape +CONVERT = convert +OPTIPNG = optipng +# Program options +EMACSOPTS = +PATTERN = .* +LANGUAGE = +ifdef LANGUAGE +SELECTOR = (language $(LANGUAGE)) +endif + +# Internal variables +EMACSBATCH = $(EMACS) -Q --batch -L . $(EMACSOPTS) +RUNEMACS = + +# Program availability +ifdef CASK +RUNEMACS = $(CASK) exec $(EMACSBATCH) +HAVE_CASK := $(shell sh -c "command -v $(CASK)") +ifndef HAVE_CASK +$(warning "$(CASK) is not available. Please run make help") +endif +else +RUNEMACS = $(EMACSBATCH) +endif +HAVE_INKSCAPE := $(shell sh -c "command -v $(INKSCAPE)") +HAVE_CONVERT := $(shell sh -c "command -v $(CONVERT)") +HAVE_OPTIPNG := $(shell sh -c "command -v $(OPTIPNG)") + +RUNTEST = $(RUNEMACS) --load test/flycheck-test --load test/run.el \ + -f flycheck-run-tests-main + +# Export Emacs to goals, mainly for CASK +CASK_EMACS = $(EMACS) +export EMACS +export CASK_EMACS + +# Run make help by default +.DEFAULT_GOAL = help + +# File lists +SRCS = flycheck.el flycheck-ert.el +OBJS = $(SRCS:.el=.elc) +IMGS = doc/_static/logo.png +TEST_SRCS = flycheck.el flycheck-ert.el test/flycheck-test.el + +# File rules +flycheck-ert.elc: flycheck.elc + +flycheck-buttercup.elc: flycheck.elc + +$(OBJS): %.elc: %.el + $(RUNEMACS) -l maint/flycheck-compile.el -f flycheck/batch-byte-compile $< + +doc/_static/logo.png: flycheck.svg +ifndef HAVE_CONVERT + $(error "$(CONVERT) not available. Please run make help.") +endif +ifndef HAVE_INKSCAPE + $(error "$(INKSCAPE) not available. Please run make help.") +endif +ifndef HAVE_OPTIPNG + $(error "$(OPTIPNG) not available. Please run make help.") +endif + $(CONVERT) $< -trim -background white -bordercolor white \ + -border 5 $@ + $(OPTIPNG) $@ + +# Public targets +.PHONY: init +init: + $(CASK) --verbose install # --verbose is workaround for Emacs 25.3 + $(CASK) update + +.PHONY: clean +clean: + rm -rf $(OBJS) + $(MAKE) -C doc clean + +.PHONY: purge +purge: + $(GIT) clean -xfd + +.PHONY: format +format: + $(RUNEMACS) -l maint/flycheck-format.el -f flycheck/batch-format + +.PHONY: check-format +check-format: + $(RUNEMACS) -l maint/flycheck-format.el -f flycheck/batch-check-format + +.PHONY: checkdoc +checkdoc: + $(RUNEMACS) -l maint/flycheck-checkdoc.el -f flycheck/batch-checkdoc + +.PHONY: check +check: check-format checkdoc + +.PHONY: compile +compile: $(OBJS) + +.PHONY: specs +specs: compile + $(CASK) exec buttercup -L . --pattern '$(PATTERN)' test/specs + +.PHONY: unit +unit: compile + $(RUNTEST) '(and (not (tag external-tool)) $(SELECTOR))' + +.PHONY: integ +integ: compile + $(RUNTEST) '(and (tag external-tool) $(SELECTOR))' + +.PHONY: images +images: $(IMGS) + +.PHONY: help +help: + @echo 'Run `make init` first to install and update all local dependencies.' + @echo '' + @echo 'Available targets:' + @echo ' init: Initialise the project. RUN FIRST!' + @echo ' check: Check all Emacs Lisp sources (needs Emacs 25)' + @echo ' compile: Byte-compile Emacs Lisp sources' + @echo ' format: Format all Emacs Lisp sources' + @echo ' specs: Run all buttercup specs for Flycheck' + @echo ' unit: Run all ERT unit tests for Flycheck (legacy)' + @echo ' integ: Run all integration tests for Flycheck' + @echo ' images: Generate PNG images from SVG sources' + @echo ' clean: Clean compiled files' + @echo ' purge: Clean everything' + @echo '' + @echo 'Available make variables:' + @echo ' PATTERN: A regular expression matching spec names to run with `specs`' + @echo ' SELECTOR: An ERT selector expression for `unit` and `integ`' + @echo ' LANGUAGE: The name of a language for `integ`. Overrides `SELECTOR`' + @echo ' EMACSOPTS: Additional options to pass to `emacs`' + @echo ' EMACS: The path or name of the Emacs to use for tests and compilation' + @echo '' + @echo 'Available programs:' + @echo ' $(CASK): $(if $(HAVE_CASK),yes,no)' + @echo '' + @echo 'You need $(CASK) to develop Flycheck.' + @echo 'See http://cask.readthedocs.io/ for more information.' diff --git a/README.md b/README.md new file mode 100644 index 0000000..2387de8 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# [![Flycheck][logo]](https://www.flycheck.org) # + +[![License GPL 3](https://img.shields.io/github/license/flycheck/flycheck.svg)][COPYING] +[![Join the chat](https://img.shields.io/gitter/room/flycheck/flycheck.svg)](https://gitter.im/flycheck/flycheck) +[![MELPA stable version](http://stable.melpa.org/packages/flycheck-badge.svg)](https://stable.melpa.org/#/flycheck) +[![Build Status](https://img.shields.io/travis/flycheck/flycheck/master.svg)](https://travis-ci.org/flycheck/flycheck) + + + +Modern on-the-fly syntax checking extension for GNU Emacs. [Try it][]! + +![](https://raw.githubusercontent.com/flycheck/flycheck/master/doc/images/flycheck-annotated.png) + +For a more gentle introduction read the [Installation][] instructions and go +through [Quickstart][] guide. + +Please ask questions about Flycheck on [Stack Exchange][sx] or in our +[Gitter chat][gitter], and report bugs to our [issue tracker][]. + +We welcome all kinds of contributions, whether you write patches, open pull +requests, write documentation, help others with Flycheck issues, or just tell +other people about your experiences with Flycheck. Please take a look at our +[Contributor’s Guide][contrib] for help and guidance about contributing to +Flycheck. + +We strive to create a safe, friendly and welcoming environment in the Flycheck +community and have a [Code of Conduct][coc] that defines acceptable and welcome +behaviour as well as sanctions for violations. All contributors and all +participants are expected to follow it, on Github, Gitter, Emacs.SX or any other +place that’s part of Flycheck’s broader community. + +Flycheck is free software: you can redistribute it and/or modify it under the +terms of the [GNU General Public License][copying] as published by the Free +Software Foundation, either version 3 of the License, or (at your option) any +later version. + +Flycheck is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the [GNU General Public License][copying] for more +details. + +[COPYING]: https://github.com/flycheck/flycheck/blob/master/COPYING +[manual]: https://www.flycheck.org/en/latest/index.html#the-user-guide +[logo]: https://raw.githubusercontent.com/flycheck/flycheck/master/doc/_static/logo.png +[try it]: https://www.flycheck.org/en/latest/#try-out +[Installation]: https://www.flycheck.org/en/latest/user/installation.html +[Quickstart]: https://www.flycheck.org/en/latest/user/quickstart.html +[sx]: https://emacs.stackexchange.com/questions/tagged/flycheck +[gitter]: https://gitter.im/flycheck/flycheck +[Issue Tracker]: https://github.com/flycheck/flycheck/issues +[contrib]: https://www.flycheck.org/en/latest/contributor/contributing.html +[coc]: https://www.flycheck.org/en/latest/community/conduct.html diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..6a97da3 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,5 @@ +# Sphinx build artifacts +/_build/ + +# Python bytecode of the in-tree Sphinx extensions +__pycache__/ \ No newline at end of file diff --git a/doc/COPYING.cc-by-sa b/doc/COPYING.cc-by-sa new file mode 100644 index 0000000..fd662a7 --- /dev/null +++ b/doc/COPYING.cc-by-sa @@ -0,0 +1,428 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..a465ed0 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,112 @@ +# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors +# This file is not part of GNU Emacs. + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +PIP = pip3 +SPHINXOPTS = -j4 +SPHINXBUILD = sphinx-build +SPHINXAUTOBUILD = sphinx-autobuild +OPTIPNG = optipng +BUILDDIR = _build + +# Whether to build offline HTML that loads no external resources, for use in 3rd +# party packages, see https://github.com/flycheck/flycheck/issues/999 +OFFLINE = + +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) . +ifdef OFFLINE +ALLSPHINXOPTS += -Dflycheck_offline_html=1 +endif + +IMAGES = images/*.png + +.DEFAULT_GOAL := help + +HAVE_SPHINXBUILD := $(shell sh -c "command -v $(SPHINXBUILD)") +ifndef HAVE_SPHINXBUILD +$(warning "$(SPHINXBUILD) is not available. Please run make help.") +endif +HAVE_SPHINXAUTOBUILD := $(shell sh -c "command -v $(SPHINXAUTOBUILD)") +HAVE_PIP := $(shell sh -c "command -v $(PIP)") + +.PHONY: help +help: + @echo 'Available targets:' + @echo ' html: Build HTML documentation to $(BUILDDIR)/html' + @echo ' html-auto: Like html, but automatically rebuild on changes' + @echo ' linkcheck: Check all links and references' + @echo ' clean: Remove generated documentation' + @echo ' optimise-images: Optimise all images in the documentation' + @echo '' + @echo 'To build the documentation you need $(SPHINXBUILD).' + @echo 'For *-auto targets you also need $(SPHINXAUTOBUILD).' + @echo '' + @echo 'Available make variables:' + @echo ' OFFLINE: If set build HTML that loads no external resources' + @echo '' + @echo 'Available programs:' + @echo ' $(SPHINXBUILD): $(if $(HAVE_SPHINXBUILD),yes,no)' + @echo ' $(SPHINXAUTOBUILD): $(if $(HAVE_SPHINXAUTOBUILD),yes,no)' + @echo '' + @echo 'You need Python 3.4 or newer to install Sphinx for Flycheck.' + @echo '' + @echo 'Run make init to install all missing tools. It is recommended' + @echo 'that you use virtualenv (https://virtualenv.pypa.io/en/latest/)' + @echo 'to avoid a global installation of Python packages. make init' + @echo 'will warn you if you do not.' + +.PHONY: init +init: +ifndef HAVE_PIP + $(error "$(PIP) not available. Please run make help.") +endif +ifndef VIRTUAL_ENV + $(warning "No virtualenv active. Installing Sphinx globally is not recommended.") +ifndef FORCE + $(error "Aborted. Run make FORCE=1 init to override or make help.") +endif +endif + pip install -r requirements.txt + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +# HTML and related formats +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: html-auto +html-auto: SPHINXOPTS = -B +html-auto: +ifndef HAVE_SPHINXAUTOBUILD + $(error "sphinx-autobuild not available. Run make help.") +endif + $(SPHINXAUTOBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + +# House-keeping targets +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: optimise-images +optimise-images: + $(OPTIPNG) $(filter %.png,$(IMAGES)) diff --git a/doc/_static/favicon.ico b/doc/_static/favicon.ico new file mode 100644 index 0000000..ff29a2f Binary files /dev/null and b/doc/_static/favicon.ico differ diff --git a/doc/_static/favicon.png b/doc/_static/favicon.png new file mode 100644 index 0000000..ccfff1e Binary files /dev/null and b/doc/_static/favicon.png differ diff --git a/doc/_static/logo.png b/doc/_static/logo.png new file mode 100644 index 0000000..4181579 Binary files /dev/null and b/doc/_static/logo.png differ diff --git a/doc/_templates/about.html b/doc/_templates/about.html new file mode 100644 index 0000000..a0e5688 --- /dev/null +++ b/doc/_templates/about.html @@ -0,0 +1,43 @@ +{% if theme_logo %} +

{{ project }}

+ {% endif %} + +

+{% else %} +

{{ project }}

+{% endif %} + +{% if theme_description %} +

{{ theme_description }}

+{% endif %} + +{% macro badge(badge, href) -%} +

+{%- endmacro %} + +{% if theme_github_user and theme_github_repo and not flycheck_offline_html %} +{% if theme_github_button|lower == 'true' %} +

+ +

+{% endif %} +{% endif %} + +{% if not flycheck_offline_html %} +

+ + + +

+

+ MELPA Stable +

+

+ MELPA +

+{% endif %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100644 index 0000000..c267e13 --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,20 @@ +{% extends "!layout.html" %} + +{% block extrahead %} + +{% endblock %} diff --git a/doc/_templates/tables.html b/doc/_templates/tables.html new file mode 100644 index 0000000..7600041 --- /dev/null +++ b/doc/_templates/tables.html @@ -0,0 +1,6 @@ +

Tables

+ diff --git a/doc/changes.rst b/doc/changes.rst new file mode 100644 index 0000000..d19089f --- /dev/null +++ b/doc/changes.rst @@ -0,0 +1,5 @@ +========= + Changes +========= + +.. include:: ../CHANGES.rst diff --git a/doc/community/conduct.rst b/doc/community/conduct.rst new file mode 100644 index 0000000..80647cf --- /dev/null +++ b/doc/community/conduct.rst @@ -0,0 +1,96 @@ +.. _flycheck-conduct: + +========================== + Flycheck Code of Conduct +========================== + +Our Code of Conduct defines the social norms and policies within Flycheck’s +community. Whenever you interact with Flycheck or Flycheck developers, whether +in our official channels or privately, you’re expected to follow this Code of +Conduct. + +Conduct +======= + +**Contact**: :ref:`Any moderator ` + +* We are committed to providing a friendly, safe and welcoming environment for + all, regardless of level of experience, gender, gender identity and + expression, sexual orientation, disability, personal appearance, body size, + race, ethnicity, age, religion, nationality, or similar personal + characteristic. +* Please avoid using overtly sexual nicknames or other nicknames that might + detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Please do not curse or use bad words. Foul language will not help us to build + a great product. +* Respect that people have differences of opinion and that every design or + implementation choice carries a trade-off and numerous costs. There is seldom + a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you + want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass + anyone. That is not welcome behaviour. We interpret the term "harassment" as + including the definition in the `Citizen Code of Conduct`_; if you have any + lack of clarity about what might be included in that concept, please read + their definition. In particular, we don't tolerate behavior that excludes + people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel + you have been or are being harassed or made uncomfortable by a community + member, please contact a :ref:`moderator ` + immediately. Whether you're a regular contributor or a newcomer, we care about + making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing + behaviour is not welcome. + +.. _Citizen Code of Conduct: http://citizencodeofconduct.org/ + +Moderation +========== + +These are the policies for upholding our community's standards of conduct in our +communication channels, most notably in Flycheck’s Github organisation and in +Flycheck’s Gitter channels. + +1. Remarks that violate the Flycheck code of conduct, including hateful, + hurtful, oppressive, or exclusionary remarks, are not allowed. +2. Remarks that moderators find inappropriate, whether listed in the code of + conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of + the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, + i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a + first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it + up with that moderator, or with a different moderator, **in + private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a + moderator creates an inappropriate situation, they should expect less leeway + than others. + +In the Flycheck community we strive to go the extra step to look out for each +other. Don't just aim to be technically unimpeachable, try to be your best +self. In particular, avoid flirting with offensive or sensitive issues, +particularly if they're off-topic; this all too often leads to unnecessary +fights, hurt feelings, and damaged trust; worse, it can drive people away from +the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be +defensive. Just stop doing what it was they complained about and apologize. Even +if you feel you were misinterpreted or unfairly accused, chances are good there +was something you could have communicated better — remember that it's your +responsibility to make your fellow Flycheck people comfortable. Everyone wants +to get along and we are all here first and foremost because we want to talk +about cool technology. You will find that people will be eager to assume good +intent and forgive as long as you earn their trust. + +--- + +Adapted from the `Rust Code of Conduct`_. + +| Copyright (c) 2015 Sebastian Wiesner and Flycheck contributors +| Copyright (c) 2014 The Rust Project Developers + +.. _Rust Code of Conduct: https://www.rust-lang.org/conduct.html diff --git a/doc/community/extensions.rst b/doc/community/extensions.rst new file mode 100644 index 0000000..14350fc --- /dev/null +++ b/doc/community/extensions.rst @@ -0,0 +1,166 @@ +.. _flycheck-extensions: + +======================== + Recommended extensions +======================== + +The Emacs community has produced a number of extensions to Flycheck. This page +lists all that we know of and can safely recommend to our users. + +*Official* extensions are (co-)maintained by the :ref:`Flycheck maintainers +` who will take care to update official extensions in case +of breaking changes in Flycheck and work to provide extra API for extensions if +needed. If you'd like to make your extension an *official* one and move it into +the `Flycheck Github organisation`_ please contact a :ref:`maintainer +`. + +If you do know extensions not in this list, or would like to see your own +extension here, please feel free to `add it`_. + +We would like to thank all people who created and contributed to Flycheck +extensions for their awesome work. Without your help and support Flycheck would +not be what it is today. + +.. _add it: https://github.com/flycheck/flycheck/edit/master/doc/community/extensions.rst +.. _Flycheck Github organisation: https://github.com/flycheck + +User interface +============== + +These extensions change Flycheck’s user interface: + +* :flyc:`flycheck-color-mode-line` (*official*) colors the mode line according + to the Flycheck status. +* :flyc:`flycheck-pos-tip` (*official*) shows Flycheck error messages in a + graphical popup. +* :gh:`liblit/flycheck-status-emoji` adds cute emoji (e.g. 😱 for errors) to + Flycheck’s mode line status. +* :gh:`Wilfred/flycheck-title` shows Flycheck error messages in the frame title. +* :flyc:`flycheck-inline` shows Flycheck error messages in the buffer, directly + below their origin. + +Language support +================ + +These extensions add support for new languages, or improve support for built-in +languages. They are grouped by the corresponding language so you can jump +directly to the languages that interest you: + +.. contents:: Languages + :local: + +Cadence +------- + +* :gh:`cmarqu/flycheck-hdl-irun` adds a syntax checker for hardware description + languages supported by `Cadence IES/irun`_. + +.. _Cadence IES/irun: https://www.cadence.com/content/cadence-www/global/en_US/home/tools/system-design-and-verification/simulation-and-testbench-verification/incisive-enterprise-simulator.html + +Clojure +------- + +* :gh:`clojure-emacs/squiggly-clojure` adds syntax checking for Clojure. + +C/C++/Objective C +----------------- + +* :gh:`Wilfred/flycheck-pkg-config` configures Flycheck to use settings from + `pkg-config`_ when checking C/C++. +* :gh:`Sarcasm/flycheck-irony` adds a Flycheck syntax checker for C, C++ and + Objective C using :gh:`Irony Mode `. + +.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/ + +D +- + +* :flyc:`flycheck-d-unittest` (*official*) adds a Flycheck checker to run unit + tests for D programs on the fly. + +Elixir +------ + +* :gh:`tomekowal/flycheck-mix` adds an Elixir syntax checker using the ``mix`` + build tool. + +Emacs Lisp +---------- + +* :flyc:`flycheck-cask` (*official*) makes Flycheck use Cask packages for Emacs + Lisp syntax checking in Cask_ projects. +* :gh:`purcell/flycheck-package` checks Emacs Lisp packages for common problems + with package metadata. + +.. _Cask: https://github.com/cask/cask + +Julia +----- + +* :gh:`gdkrmr/flycheck-julia` makes linting for Julia_ available via Lint.jl_. + +.. _Julia: https://julialang.org +.. _Lint.jl: https://lintjl.readthedocs.io/en/stable/ + +Haskell +------- + +* :flyc:`flycheck-haskell` (*official*) configures Flycheck from the Cabal + settings and sandbox in Haskell projects. + +Ledger +------ + +* :gh:`purcell/flycheck-ledger` adds a syntax checker for the Ledger_ accounting + tool. + +.. _Ledger: https://ledger-cli.org/ + +Mercury +------- + +* :flyc:`flycheck-mercury` (*official*) adds a syntax checker for the Mercury_ + language. + +.. _Mercury: http://mercurylang.org/ + +OCaml +----- + +* :flyc:`flycheck-ocaml` (*official*) adds a syntax checker for OCaml using the + :gh:`Merlin ` backend. + +PHP +--- + +* :gh:`emacs-php/phpstan.el` adds a PHP static analyzer using PHPStan_. +* :gh:`emacs-php/psalm.el` adds a PHP static analyzer using Psalm_. + +.. _PHPStan: https://phpstan.org/ +.. _Psalm: https://psalm.dev/ + +Python +------ + +* :gh:`Wilfred/flycheck-pyflakes` adds a Python syntax checker using Pyflakes_. +* :gh:`msherry/flycheck-pycheckers` adds a checker for Python that can run multiple syntax checkers simultaneously (Pyflakes_, PEP8, Mypy_ 2/3, etc.). +* :gh:`chocoelho/flycheck-prospector` adds Prospector_ checker for Python syntax. + +.. _Pyflakes: https://github.com/PyCQA/pyflakes +.. _Prospector: https://github.com/PyCQA/prospector +.. _Mypy: http://mypy-lang.org/ + +Rust +---- + +* :flyc:`flycheck-rust` (*official*) configures Flycheck according to the Cargo + settings and layouts of the current Rust project. + +Shell scripts +------------- + +* :gh:`Gnouc/flycheck-checkbashisms` adds a shell script syntax checker using + ``checkbashisms`` which is part of `Debian devscripts`_ and checks for common + Bash constructs in POSIX shell scripts. + +.. _Debian devscripts: https://salsa.debian.org/debian/devscripts diff --git a/doc/community/get-help.rst b/doc/community/get-help.rst new file mode 100644 index 0000000..27ab1e8 --- /dev/null +++ b/doc/community/get-help.rst @@ -0,0 +1,17 @@ +.. _flycheck-get-help: + +========== + Get help +========== + +Please ask questions about Flycheck on `Stack Exchange`_ or in our `Gitter +chat`_. We try to answer all questions as fast and as precise as possible. + +To report bugs and problems please please use our :flyc:`issue tracker +`. Please note that we have a special policy for +:ref:`Windows-only issues `. + +Please follow our :ref:`Code of Conduct ` in all these places. + +.. _Stack Exchange: https://emacs.stackexchange.com/questions/tagged/flycheck +.. _Gitter chat: https://gitter.im/flycheck/flycheck diff --git a/doc/community/people.rst b/doc/community/people.rst new file mode 100644 index 0000000..c06d1b9 --- /dev/null +++ b/doc/community/people.rst @@ -0,0 +1,293 @@ +======== + People +======== + +.. _flycheck-teams: + +Teams +===== + +.. _flycheck-maintainers: + +Maintainers +----------- + +* **Clément Pit-Claudel** (:gh:`cpitclaudel`, owner) +* **fmdkdd** (:gh:`fmdkdd`, owner) + +We maintain Flycheck and all official extensions within the `Flycheck +organisation`_, and set the direction and scope of Flycheck. We review and +accept pull requests and feature proposals and fix bugs in Flycheck. + +Emphasized users are also owners of the `Flycheck Organisation`_, and thus have +administrative privileges for all repositories in Flycheck. Notably only owners +can currently make Flycheck releases, and their GPG keys sign release tags for +Flycheck. + +Mention with ``@flycheck/maintainers``. + +.. _Flycheck Organisation: https://github.com/flycheck + +.. _flycheck-moderators: + +Moderators +---------- + +Our moderators help uphold our :doc:`conduct`. Currently, we do not have a +dedicated moderation team; all our :ref:`flycheck-maintainers` also serve as +moderators in our Github organisation and in our official communication +channels. + +Mention with ``@flycheck/moderators``. + +.. note:: + + If you’d like to help out with moderation, please contact a maintainer. + +.. _flycheck-language-teams: + +Language teams +-------------- + +These teams provide support for particular languages in Flycheck. + +Elixir +~~~~~~ + +* Aaron Jensen (:gh:`aaronjensen`) +* Kári Tristan Helgason (:gh:`kthelgason`) + +Mention with ``@flycheck/elixir``. + +Go +~~ + +* Dominik Honnef (:gh:`dominikh`) + +Mention with ``@flycheck/go``. + +Haskell +~~~~~~~ + +* Sergey Vinokurov (:gh:`sergv`) +* Steve Purcell (:gh:`purcell`) + +Mention with ``@flycheck/haskell``. + +Javascript +~~~~~~~~~~ + +* Saša Jovanić (:gh:`Simplify`) + +Mention with ``@flycheck/javascript``. + +Lua +~~~ + +* Gordon Gao (:gh:`ghprince`) + +Mention with ``@flycheck/lua``. + +Mercury +~~~~~~~ + +* Matthias Güdemann (:gh:`mgudemann`) + +Mention with ``@flycheck/mercury``. + +PHP +~~~ + +* USAMI Kenta (:gh:`zonuexe`) + +Mention with ``@flycheck/php``. + +Puppet +~~~~~~ + +* Romanos Skiadas (:gh:`rski`) + +Mention with ``@flycheck/puppet``. + +Ruby +~~~~ + +* Saša Jovanić (:gh:`Simplify`) + +Mention with ``@flycheck/javascript``. + +Rust +~~~~ + +* :gh:`fmdkdd` +* Michael Pankov (:gh:`mkpankov`) + +Mention with ``@flycheck/rust``. + +TypeScript +~~~~~~~~~~ + +* Saša Jovanić (:gh:`Simplify`) + +Mention with ``@flycheck/typescript``. + +Packagers +========= + +We would like to thank all people who package Flycheck on behalf of +distributions and support our development efforts with their feedback, their +patches and their testing: + +* Sean Whitton (:gh:`spwhitton`) and the `Debian Emacs addon team`_ (Debian + packages) + +.. _Debian Emacs addon team: https://pkg-emacsen.alioth.debian.org/ + +Acknowledgements +================ + +We would also like to thank the following people and projects: + +* Sebastian Wiesner (:gh:`lunaryorn`) for creating Flycheck in the first place, + for taking the time and dedication to maintain it for over 4 years, while + maintaining high standards of code quality and nurturing a healthy, active + community around it, giving Flycheck the best chances to thrive after his + departure. +* Bozhidar Batsov (:gh:`bbatsov`) for his valuable feedback and his constant + support and endorsement of Flycheck from the very beginning. Notably he added + Flycheck to his popular :gh:`Prelude ` project at a very + early stage and thus brought Flycheck to many new users. +* Magnar Sveen (:gh:`magnars`) for his :gh:`dash.el ` and + :gh:`s.el ` libraries, which support considerable parts of + Flycheck internals, and greatly helped to overcome Sebastian’s initial + aversion to Emacs Lisp. +* Martin Grenfell (:gh:`scrooloose`) for the Vim syntax checking extension + :gh:`Syntastic ` which saved Sebastian’s life back + when he was using Vim, and served as inspiration for Flycheck and many of its + syntax checkers. +* Matthias Güdemann (:gh:`mgudemann`), for his invaluable work on + Flycheck’s logo. +* Pavel Kobyakov for his work on GNU Flymake, which is a great work on + its own, despite its flaws and weaknesses. +* Simon Carter (:gh:`bbbscarter`), for his patient in-depth testing of automatic + syntax checking, and his very constructive feedback. +* Steve Purcell (:gh:`purcell`) for his valuable feedback, the fruitful + discussions and his important ideas about the shape and design of Flycheck, + and his indispensable and dedicated work on MELPA, which drives the continuous + distribution of Flycheck to its users. + +Contributors +============ + +The following people—listed in alphabetical order—contributed substantial code +to Flycheck: + +* Aaron Jensen (:gh:`aaronjensen`) +* Alain Kalker (:gh:`ackalker`) +* Alex Reed (:gh:`acr4`) +* Atila Neves (:gh:`atilaneves`) +* Ben Sless (:gh:`bsless`) +* Bozhidar Batsov (:gh:`bbatsov`) +* Clément Pit-Claudel (:gh:`cpitclaudel`, maintainer, owner) +* Colin Marquardt (:gh:`cmarqu`) +* Cristian Capdevila (:gh:`capdevc`) +* Damon Haley (:gh:`dhaley`) +* David Caldwell (:gh:`caldwell`) +* David Holm (:gh:`dholm`) +* DEADB17 (:gh:`DEADB17`) +* Deokhwan Kim (:gh:`dkim`) +* Derek Chen-Becker (:gh:`dchenbecker`) +* Derek Harland (:gh:`donkopotamus`) +* Dominik Honnef (:gh:`dominikh`) +* Doug MacEachern (:gh:`dougm`) +* Drew Wells (:gh:`drewwells`) +* Erik Hetzner (:gh:`egh`) +* Fanael Linithien (:gh:`Fanael`) +* :gh:`fmdkdd` (maintainer, owner) +* Fred Morcos (:gh:`fredmorcos`) +* Gereon Frey (:gh:`gfrey`) +* Gordon Gao (:gh:`ghprince`) +* Guido Kraemer (:gh:`gdkrmr`) +* Gulshan Singh (:gh:`gsingh93`) +* Iain Beeston (:gh:`iainbeeston`) +* Ibrahim Awwal (:gh:`ibrahima`) +* Jackson Ray Hamilton (:gh:`jacksonrayhamilton`) +* Jim Hester (:gh:`jimhester`) +* Jimmy Yuen Ho Wong (:gh:`wyuenho`) +* Joe DeVivo (:gh:`joedevivo`) +* John Shahid (:gh:`jvshahid`) +* Juergen Hoetzel (:gh:`juergenhoetzel`) +* Kári Tristan Helgason (:gh:`kthelgason`) +* Krzysztof Witkowski (:gh:`kwitek`) +* Lee Adams (:gh:`leeaustinadams`) +* Loïc Damien (:gh:`dzamlo`) +* Lorenzo Villani (:gh:`lvillani`) +* Łukasz Jędrzejewski (:gh:`jedrz`) +* Magnar Sveen (:gh:`magnars`) +* Malyshev Artem (:gh:`proofit404`) +* Manuel Uberti (:gh:`manuel-uberti`) +* Marc Sherry (:gh:`msherry`) +* Marcin Antczak (:gh:`marcinant`) +* Marcus Majewski (:gh:`hekto`) +* Marian Schubert (:gh:`maio`) +* Mario Rodas (:gh:`marsam`) +* Mark Laws (:gh:`drvink`) +* Mark Hellewell (:gh:`markhellewell`) +* Mark Karpov (:gh:`mrkkrp`) +* Martin Polden (:gh:`mpolden`) +* mats cronqvist (:gh:`massemanet`) +* Matthew Curry (:gh:`strawhatguy`) +* Matthias Dahl (:gh:`BinaryKhaos`) +* Michael Pankov (:gh:`mkpankov`) +* Michael Alan Dorman (:gh:`mdorman`) +* Miles Yucht (:gh:`mgyucht`) +* Miro Bezjak (:gh:`mbezjak`) +* Mitch Tishmack (:gh:`mitchty`) +* Moritz Bunkus (:gh:`mbunkus`) +* Omair Majid (:gh:`omajid`) +* :gh:`papaeye` +* Per Nordlöw (:gh:`nordlow`) +* Peter Eisentraut (:gh:`petere`) +* Peter Hoeg (:gh:`peterhoeg`) +* Peter Oliver (:gh:`mavit`) +* Peter Vasil (:gh:`ptrv`) +* Philipp Stephani (:gh:`phst`) +* Robert Dallas Gray (:gh:`rdallasgray`) +* Robert O'Connor (:gh:`robbyoconnor`) +* Robert Zaremba (:gh:`robert-zaremba`) +* Romano Skiadas (:gh:`rski`) +* Saša Jovanić (:gh:`Simplify`) +* Sean Gillespie (:gh:`swgillespie`) +* Sean Salmon (:gh:`phatcabbage`) +* Sean Whitton (:gh:`spwhitton`) +* Sebastian Beyer (:gh:`sebastianbeyer`) +* Sebastian Wiesner (:gh:`lunaryorn`, founder, former maintainer, former owner) +* Sebastian Schlueppel (:gh:`s3bs`) +* Sergey Vinokurov (:gh:`sergv`) +* Stephen Lewis (:gh:`stephenjlewis`) +* Steve Purcell (:gh:`purcell`) +* Sven Keidel (:gh:`svenkeidel`) +* Sylvain Benner (:gh:`syl20bnr`) +* Sylvain Rousseau (:gh:`thisirs`) +* Syohei Yoshida (:gh:`syohex`) +* Ted Zlatanov (:gh:`tzz`) +* Tom Jakubowski (:gh:`tomjakubowski`) +* Tom Willemse (:gh:`ryuslash`) +* Tomoya Tanjo (:gh:`tom-tan`) +* Troy Hinckley (:gh:`CeleritasCelery`) +* Usami Kenta (:gh:`zonuexe`) +* Victor Deryagin (:gh:`vderyagin`) +* Ville Skyttä (:gh:`scop`) +* Vlatko Basic (:gh:`vlatkoB`) +* Wieland Hoffmann (:gh:`mineo`) +* Wilfred Hughes (:gh:`Wilfred`) +* William Cummings (:gh:`wcummings`) +* William Xu (:gh:`xwl`) +* Yannick Roehlly (:gh:`yannick1974`) +* Yasuyuki Oka (:gh:`yasuyk`) +* Zhuo Yuan (:gh:`yzprofile`) + +For a complete list of all code contributors see the `Contributor Graph`_ or +``git shortlog --summary``. + +.. _Contributor Graph: https://github.com/flycheck/flycheck/graphs/contributors diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..c130f9a --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,302 @@ +# Copyright (C) 2017, 2018 Flycheck contributors +# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +# This file is not part of GNU Emacs. + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +import re +import sys +import os +from pathlib import Path +from docutils import nodes +from docutils.statemachine import ViewList +from docutils.transforms import Transform +from docutils.parsers.rst import Directive, directives +from sphinx import addnodes +from sphinx.util.nodes import set_source_info, process_index_entry +from sphinx.util import logging + +logger = logging.getLogger(__name__) + +sys.path.append(str(Path(__file__).parent)) + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +needs_sphinx = '1.3' +extensions = [ + 'sphinx.ext.intersphinx', + 'sphinx.ext.extlinks', + 'sphinx.ext.todo', + # Domain for Emacs Lisp + 'elisp', + # Cross-references to info nodes + 'info' +] + +# Project metadata +project = 'Flycheck' +copyright = ' 2014-2017, Sebastian Wiesner and Flycheck contributors' +author = 'Sebastian Wiesner' + + +def read_version(): + """Extract version number from ``flycheck.el`` and return it as string.""" + version_pattern = re.compile(r'^;;\s*Version:\s+(\d.+)$', re.MULTILINE) + flycheck = Path(__file__).resolve().parent.parent.joinpath('flycheck.el') + with flycheck.open(encoding='utf-8') as source: + match = version_pattern.search(source.read()) + if match: + return match.group(1) + else: + raise ValueError('Failed to parse Flycheck version from ' + 'Version: of flycheck.el') + + +def read_minimum_emacs_version(): + """Extract minimum Emacs version from ``flycheck.el``.""" + version_pattern = re.compile( + r'^;; Package-Requires:.*\(emacs\s*"([^"]+)"\).*$', re.MULTILINE) + flycheck = Path(__file__).resolve().parent.parent.joinpath('flycheck.el') + with flycheck.open(encoding='utf-8') as source: + match = version_pattern.search(source.read()) + if match: + return match.group(1) + else: + raise ValueError('Vailed to parse minimum Emacs version from ' + 'Package-Requires of flycheck.el!') + + +release = read_version() +version = '.'.join(release.split('.')[:2]) + +# Source settings +source_suffix = '.rst' +master_doc = 'index' + +rst_prolog = """\ +.. role:: elisp(code) + :language: elisp + +.. |min-emacs| replace:: {emacs_version}+ +""".format(emacs_version=read_minimum_emacs_version()) + +# Build settings +exclude_patterns = ['_build'] +default_role = 'any' +primary_domain = 'el' +templates_path = ['_templates'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# Warn about all undefined references, but exclude references to built-in +# symbols which we don't document here. +# TODO: Resolve built-in symbols to the Emacs Lisp references? +nitpicky = True +nitpick_ignore = [ + ('any', 'default-directory'), + ('any', 'package-initialize'), + ('any', 'package-archives'), + ('any', 'user-init-file'), + ('any', 'user-emacs-directory'), + ('any', 'check-declare-file'), + ('any', 'declare-function'), + ('any', 'exec-path'), + ('any', 'sh-shell'), + ('any', 'rx'), +] + +# HTML settings +html_theme = 'alabaster' +html_theme_options = { + 'logo': 'logo.png', + 'logo_name': False, + 'description': 'Syntax checking for GNU Emacs', + 'github_user': 'flycheck', + 'github_repo': 'flycheck', + 'github_type': 'star', + 'github_banner': True, + 'travis_button': False, +} +html_sidebars = { + '**': [ + 'about.html', + 'tables.html', + 'navigation.html', + 'relations.html', + 'searchbox.html', + ] +} +html_static_path = ['_static'] +html_favicon = '_static/favicon.ico' + +# Ignore localhost when checking links +linkcheck_ignore = [r'http://localhost:\d+/?'] + +# Cross-reference remote Sphinx sites +intersphinx_mapping = { + 'python': ('https://docs.python.org/3.5', None) +} + +extlinks = { + 'gh': ('https://github.com/%s', ''), + 'flyc': ('https://github.com/flycheck/%s', '') +} + +# While still have work to do :) +# FIXME: Remove when the old Texinfo manual is completed ported +todo_include_todos = True + + +class SupportedLanguage(Directive): + + required_arguments = 1 + final_argument_whitespace = True + has_content = True + option_spec = { + 'index_as': directives.unchanged + } + + def run(self): + language = self.arguments[0] + + indexed_languages = self.options.get('index_as') or language + index_specs = ['pair: {}; language'.format(lang) + for lang in indexed_languages.splitlines()] + + name = nodes.fully_normalize_name(language) + target = 'language-{}'.format(name) + targetnode = nodes.target('', '', ids=[target]) + self.state.document.note_explicit_target(targetnode) + + indexnode = addnodes.index() + indexnode['entries'] = [] + indexnode['inline'] = False + set_source_info(self, indexnode) + for spec in index_specs: + indexnode['entries'].extend(process_index_entry(spec, target)) + + sectionnode = nodes.section() + sectionnode['names'].append(name) + + title, messages = self.state.inline_text(language, self.lineno) + titlenode = nodes.title(language, '', *title) + + sectionnode += titlenode + sectionnode += messages + self.state.document.note_implicit_target(sectionnode, sectionnode) + + self.state.nested_parse(self.content, self.content_offset, sectionnode) + + return [indexnode, targetnode, sectionnode] + + +class SyntaxCheckerConfigurationFile(Directive): + + required_arguments = 1 + final_argument_whitespace = True + + def run(self): + option = self.arguments[0] + + wrapper = nodes.paragraph() + docname = self.state.document.settings.env.docname + template = ViewList("""\ +.. index:: single: Configuration file; {0} + +.. el:defcustom:: {0} + + Configuration file for this syntax checker. See + :ref:`flycheck-checker-config-files`. +""".format(option).splitlines(), docname) + self.state.nested_parse(template, self.content_offset, wrapper) + + return wrapper.children.copy() + + +class IssueReferences(Transform): + + ISSUE_PATTERN = re.compile(r'\[GH-(\d+)\]') + ISSUE_URL_TEMPLATE = 'https://github.com/flycheck/flycheck/issues/{}' + + default_priority = 999 + + def apply(self): + docname = self.document.settings.env.docname + if docname != 'changes': + # Only transform issue references in changelo + return + + for node in self.document.traverse(nodes.Text): + parent = node.parent + new_nodes = [] + last_issue_ref_end = 0 + text = str(node) + for match in self.ISSUE_PATTERN.finditer(text): + # Extract the text between the last issue reference and the + # current issue reference and put it into a new text node + head = text[last_issue_ref_end:match.start()] + if head: + new_nodes.append(nodes.Text(head)) + # Adjust the position of the last issue reference in the + # text + last_issue_ref_end = match.end() + # Extract the issue text and the issue number + issuetext = match.group(0) + issue_id = match.group(1) + # Turn the issue into a proper reference + refnode = nodes.reference() + refnode['refuri'] = self.ISSUE_URL_TEMPLATE.format(issue_id) + refnode.append(nodes.inline( + issuetext, issuetext, classes=['xref', 'issue'])) + new_nodes.append(refnode) + + # No issue references were found, move on to the next node + if not new_nodes: + continue + # Extract the remaining text after the last issue reference + tail = text[last_issue_ref_end:] + if tail: + new_nodes.append(nodes.Text(tail)) + parent.replace(node, new_nodes) + + +def build_offline_html(app): + from sphinx.builders.html import StandaloneHTMLBuilder + build_standalone = isinstance(app.builder, StandaloneHTMLBuilder) + if app.config.flycheck_offline_html and build_standalone: + logger.info( + 'Building offline documentation without external resources!') + app.builder.theme_options['github_banner'] = 'false' + app.builder.theme_options['github_button'] = 'false' + + +def add_offline_to_context(app, _pagename, _templatename, context, _doctree): + # Expose offline setting in HTML context + context['flycheck_offline_html'] = app.config.flycheck_offline_html + + +def setup(app): + app.add_object_type('syntax-checker', 'checker', + 'pair: %s; Syntax checker') + app.add_directive('supported-language', SupportedLanguage) + app.add_directive('syntax-checker-config-file', + SyntaxCheckerConfigurationFile) + app.add_transform(IssueReferences) + # Build offline HTML that loads no external resources, for use in 3rd party + # packages, see https://github.com/flycheck/flycheck/issues/999 + app.add_config_value('flycheck_offline_html', False, 'html') + app.connect('builder-inited', build_offline_html) + app.connect('html-page-context', add_offline_to_context) diff --git a/doc/contributor/contributing.rst b/doc/contributor/contributing.rst new file mode 100644 index 0000000..e805d04 --- /dev/null +++ b/doc/contributor/contributing.rst @@ -0,0 +1,274 @@ +.. _flycheck-contributors-guide: + +===================== + Contributor’s Guide +===================== + +Thank you very much for your interest in contributing to Flycheck! We’d like to +warmly welcome you in the Flycheck community, and hope that you enjoy your time +with us! + +There are many ways to contribute to Flycheck, and we appreciate all of them. We +hope that this document helps you to contribute. If you have questions, please +ask on our `issue tracker`_ or in our `Gitter chatroom`_. + +For a gentle start please take a look at all the things we `need your help +with`_ and look for `beginner-friendly tasks`_. + +Please note that all contributors are expected to follow our :ref:`Code of +Conduct `. + +.. _issue tracker: https://github.com/flycheck/flycheck/issues +.. _Gitter chatroom: https://gitter.im/flycheck/flycheck +.. _need your help with: https://github.com/flycheck/flycheck/issues?q=is%3Aissue+is%3Aopen+label%3A%22needs+help%22 +.. _beginner-friendly tasks: https://github.com/flycheck/flycheck/labels/beginner%20friendly + +.. _flycheck-bug-reports: + +Bug reports +=========== + +Bugs are a sad reality in software, but we strive to have as few as possible in +Flycheck. Please liberally report any bugs you find. If you are not sure whether +something is a bug or not, please report anyway. + +If you have the chance and time please `search existing issues`_, as it’s +possible that someone else already reported your issue. Of course, this doesn’t +always work, and sometimes it’s very hard to know what to search for, so this is +absolutely optional. We definitely don’t mind duplicates, please report +liberally. + +To open an issue simply fill out the `issue form`_. To help us fix the issue, +include as much information as possible. When in doubt, better include too much +than too little. Here’s a list of facts that are important: + +* What you did, and what you expected to happen instead +* Whether and how you were able to `reproduce the issue in emacs -Q`_ +* Your Flycheck setup from ``M-x flycheck-verify-setup`` + +.. _search existing issues: https://github.com/flycheck/flycheck/issues?q=is%3Aissue +.. _issue form: https://github.com/flycheck/flycheck/issues/new +.. _reproduce the issue in emacs -Q: https://emacs.stackexchange.com/questions/28429/how-do-i-troubleshoot-emacs-problems + + +.. _flycheck-windows-issues: + +Windows-only issues +------------------- + +As Flycheck does not support Windows officially we generally do *not* attempt to +fix issues that only occur on Windows. We will move all Windows-only issues to +the `list of open Windows issues`_, and leave them to Windows users and +developers. + +We welcome anyone who wants to fix open Windows issues, and we will merge pull +requests for improved Windows compatibility. If you know Windows and Emacs, +please take a look at the list of open Windows issues and try to fix any of +these. + +.. _list of open Windows issues: https://github.com/flycheck/flycheck/labels/arch%3A%20windows%20only + +Feature requests +================ + +To request a new feature please open a new issue through our `issue form`_. +A feature request needs to find a core developer or maintainer who adopts and +implements it. + +The build system +================ + +Flycheck provides a :file:`Makefile` with some convenient targets to compile and +test Flycheck. The Makefile requires Cask_, the Emacs Lisp dependency manager. +Run ``make help`` to see a list of all available targets. Some common ones are: + +- ``make init`` initialises the project by installing local Emacs Lisp + dependencies. +- ``make check`` checks all Emacs Lisp sources. This target requires Emacs 25. +- ``make compile`` compiles Flycheck and its libraries to byte code. +- ``make format`` formats all Emacs Lisp sources. +- ``make specs`` runs all Buttercup_ specs for Flycheck. Set :makevar:`PATTERN` + to run only specs matching a specific regular expression, e.g. ``make + PATTERN='^Mode Line' specs`` to run only tests for the mode line. +- ``make unit`` runs all ERT unit tests for Flycheck. We are phasing ERT out in + favour of Buttercup; no new ERT unit tests will be added and this target will + eventually be removed. +- ``make integ`` runs all integration tests for Flycheck syntax checkers. These + tests are dependent on the checker programs and their versions; expect + failures when running this target with bleeding-edge checkers. Set + :makevar:`SELECTOR` to run only tests matching a specific ERT selector, + e.g. ``make SELECTOR='(language haskell)' integ`` to run only integration + tests for Haskell. ``make LANGUAGE=haskell integ`` is a shortcut for this. + + If you want to replicate the integration tests that are run on the CI, + continue reading. + +.. _Cask: http://cask.readthedocs.io/ +.. _Buttercup: https://github.com/jorgenschaefer/emacs-buttercup + +Running all the integration tests +================================= + +To run all the integration tests, you need to have all the syntax checkers +installed. As that can be tedious work, and since your locally installed tools +can have different versions than the tools used on the CI, we have created a +Docker image with most of the supported checkers. To use the Docker image +locally and replicate the integration tests that are run on the CI, first you +need to build the image:: + + cd flycheck + docker pull flycheck/emacs-cask:26.2 + docker pull flycheck/all-tools:latest + docker build --build-arg EMACS_VERSION=26.2 --tag tools-and-emacs:26.2 -f .travis/tools-and-emacs . + +Replace ``26.2`` by the Emacs version you want to test. See the available +versions on `docker hub`_. + +Once the image is built, you can use it to run the integration tests:: + + docker run --rm -it -v `pwd`:/flycheck --workdir /flycheck tools-and-emacs:26.2 /bin/bash -c "make integ" + +Note that the ``all-tools`` image is rebuilt each month, so the versions of the +its syntax checkers will change accordingly. You can check the version of each +installed tool by running the ``check-tools`` script in the image:: + + docker run --rm -it -v `pwd`:/flycheck --workdir /flycheck tools-and-emacs:26.2 check-tools + +.. _docker hub: https://hub.docker.com/r/flycheck/emacs-cask/tags + +Pull requests +============= + +Pull Requests are the primary mechanism to submit your own changes to +Flycheck. Github provides great documentation about `Pull Requests`_. + +.. _Pull Requests: https://help.github.com/articles/using-pull-requests/ + +Please make your pull requests against the ``master`` branch. + +Use ``make check specs unit`` to test your pull request locally. When making +changes to syntax checkers of a specific language, it’s also a good idea to run +:samp:`make LANGUAGE={language} integ` and check whether the tests for the +particular language still work. A successful ``make integ`` is by no means +mandatory for pull requests, though, the continuous integration will test your +changes, too. + +.. important:: + + To contribute to Flycheck you must sign our CLA_ (Contributor License + Agreement). The CLA Assistant bot will automatically ask you to do this when + you open a pull request, and will let you sign the CLA through your Github + account. + + We require this process mostly to make you aware of the licensing + implications of contributing to Flycheck and to obtain your explicit approval + of our licenses for your contribution. + + .. _CLA: https://gist.github.com/lunaryorn/c9c0d656fe7e704da2f734779242ec99 + +All pull requests go through a two-stage review process: + +* :ref:`Maintainer ` review the general idea and direction + of the pull request and leave a ``LGTM`` comment if they believe that the + change is a good addition to Flycheck. We currently require at least one + approval from a maintainer. +* :ref:`All contributors `—language teams in + particular—check the technical implementation of a pull request through `pull + request reviews`_, and either approve it or request changes. We currently + require at least one approval and no requested changes. + +.. important:: + + We have a comprehensive :ref:`flycheck-style-guide` that explains what + features we will accept, how our code should look likewise, what tests we + require, how commit messages should look like, and so on. + + Take a look at it to see what we look for in a code review. + +Additionally all pull requests go through automated tests on `Travis CI`_ which +check code style, run unit tests, etc + +Feel free to mention individual contributors or entire teams +(e.g. ``@flycheck/maintainers`` or ``@flycheck/javascript``) to ask for help or +feedback or request a review. Please mention the maintainers +(``@flycheck/maintainers``) if you think that your pull request has been waiting +for review too long. You can expect a first response to any pull request in a +couple of days. + +Once the pull request passed review and automated tests we will merge it. We +may also ask you whether you'd like to join Flycheck and help us, thus giving +you commit access to our repository and let you merge your own pull request. + +.. _pull request reviews: https://help.github.com/articles/about-pull-request-reviews/ +.. _Travis CI: https://travis-ci.org/flycheck/flycheck/pull_requests + +Writing documentation +===================== + +Documentation improvements are very welcome. Flycheck’s manual is written in +reStructuredText_ and built with Sphinx_. The source of the manual resides in +the ``doc/`` directory. + +You need Python 3.4 or newer to install Sphinx_ for Flycheck’s documentation. +On macOS it is recommended that you use Homebrew_ to install the latest Python +version with ``brew install python3``. On Linux you should be able to obtain +Python 3.4 from the package manager of your distribution. + +With Python 3 installed change into the ``doc/`` directory and run ``make init`` +to install Sphinx and related tools required for Flycheck’s documentation. We +recommend that you use virtualenv_ to avoid a global installation of Python +modules. ``make init`` will warn you if you do not. + +When editing documentation run ``make html-auto`` to view the results of your +edits. This target runs a local webserver at http://localhost:8000 which serves +the HTML documentation and watches the documentation sources for changes to +rebuild automatically. When you have finished your edits it is a good idea to +run ``make linkcheck`` to verify all links in the documentation. Note that this +target can take a while especially when run on a clean build. + +Run ``make help`` to see a list of all available Make targets for the +documentation. + +Documentation pull requests work in the same way as other pull requests. To +find documentation issues sort by the `documentation`_ label. + +.. _ReStructuredText: http://docutils.sourceforge.net/rst.html +.. _Sphinx: http://www.sphinx-doc.org +.. _Homebrew: https://brew.sh +.. _virtualenv: https://virtualenv.pypa.io/en/latest/ +.. _documentation: https://github.com/flycheck/flycheck/labels/documentation + +Issue management +================ + +We use Github labels for basic issue management: + +- **The red “bug” label denotes critical bugs in Flycheck that must be fixed + urgently.** +- Violet labels describe the area of Flycheck the issue belongs to. +- The green “beginner friendly” label denotes easy tasks for newcomers to the + project. +- Orange labels denote blockers. +- Grey labels indicate resolutions to issues. + +Out of tree contributions +========================= + +There are many ways that you can contribute to Flycheck that go beyond +this repository. + +Answer questions in our `Gitter channel`_ or on StackExchange_. + +Participate in Flycheck discussions in other Emacs communities and help +users with troubles. + +Write :ref:`extensions for Flycheck `. + +.. _Gitter channel: https://gitter.im/flycheck/flycheck +.. _StackExchange: https://emacs.stackexchange.com/questions/tagged/flycheck + +-------------- + +This contributing guide is heavily inspired by `Rust’s excellent +contributing +information `__. diff --git a/doc/contributor/maintaining.rst b/doc/contributor/maintaining.rst new file mode 100644 index 0000000..2fe328f --- /dev/null +++ b/doc/contributor/maintaining.rst @@ -0,0 +1,306 @@ +.. _flycheck-maintainers-guide: + +==================== + Maintainer’s Guide +==================== + +Issue triage +============ + +Please label incoming tickets accordingly according to these rules: + +- Add the “bug” label to things that you think **must be fixed urgently**. + Please don’t use this label for bugs that do not severely impede Flycheck’s + functionality. +- Add the “needs review” label to new bugs and pull requests that need to be + reviewed. +- Add the “beginner friendly” label to really easy things. If you add this + label please also add a comment that outlines a possible solution. +- Add “blocked” to bugs that need further comment or help from the reporter, and + to pull requests that need to be improved. +- Add “needs help” to anything that no contributor will work on, to mark the + issue as available for external contributors and inform users that we will not + work on the issue. +- Add “windows only” for bugs that appear to only affect Windows operating + systems. + +**If you’d like to review a bug or pull request please assign the corresponding +ticket to you.** + +In issues for specific languages that Flycheck support please mention the +corresponding :ref:`language team ` if one exists. + +Git workflow +============ + +Our Git workflow is simple: + +* The ``master`` branch is always shippable. +* Every feature and every non-trivial change goes through a pull request. + +GitHub calls this the “GitHub Flow” and has a very nice `visual guide`_ for this +model. + +.. _visual guide: https://guides.github.com/introduction/flow/ + +.. _flycheck-branch-rules: + +Branch rules +------------ + +Our workflow implies a couple of rules about which branches to push code to: + +* Please commit new features, larger changes and refactorings and updates to + documentation to separate branches and open a pull request for review and + discussion. +* The ``master`` branch is protected. Only :ref:`owners ` + can push directly to it. Everyone else needs to open a pull request. Github + requires maintainer approval and passing Travis CI tests before a pull request + can be merged to master. + +.. important:: + + When creating a new branch please use a *descriptive name* to communicate the + purpose of the branch to other developers and maintainers. ``fix-bug-42`` is + not a great name, but ``42-fix-void-function-error-in-error-list`` is. + +.. _pull request: https://help.github.com/articles/using-pull-requests/ + +.. _flycheck-pull-requests-reviews: + +Pull requests reviews +--------------------- + +We review all pull requests, and require two different kinds of approval: + +* At least one maintainer must approve the idea and direction with a ``LGTM`` + comment. +* At least one contributor (maintainer or otherwise) must approve the + implementation by leaving an approved `pull request review`_, and no + contributors must have requested changes. + +.. _pull request review: https://help.github.com/articles/about-pull-request-reviews/ + +As a maintainer +~~~~~~~~~~~~~~~ + +* Consider whether you personally think that the change is a good addition to + Flycheck. +* Weight the expected benefits and impact of the feature against the + expected complexity. +* Check whether the pull request complies with our :ref:`style guide + `, but don't go too much into technical details. +* Don't review for technical details. It's the idea and direction that counts. + +If you would like to see the pull request in Flycheck leave a ``LGTM`` comment. + +As a contributor +~~~~~~~~~~~~~~~~ + +* Check the technical implementation. +* Consider the impact on syntax checking for a language. +* Check whether the tests pass. +* Check whether the PR complies with our :ref:`style guide + `. +* Challenge the technical implementation of a pull request, and ask questions + about dubious code. +* Consider whether there might be a simpler approach or a better solution to the + problem that the PR solves. + +If you find any issues please leave a `pull request review`_ that requests +for changes. Please try to leave an inline comment wherever possible and try to +suggest a better solution, to make it easy for the PR author to discover and fix +the issues. + +If you didn't find any issues leave a `pull request review`_ that approves the +changes. + +In doubt request changes first and let the PR author explain their intention and +implementation. You can still approve the review afterwards if you are +satisfied. + +Merge guidelines +~~~~~~~~~~~~~~~~ + +Any contributor may merge approved pull requests. Our protection rules for the +``master`` branch ensure that only approved pull requests can be merged, but you +still have to check a few things before merging: + +* Are commits squashed? Before merging please take an extra look at the commits + to make sure that the commits were properly squashed and have good commit + messages. If needed, ask the contributor to improve the commit messages and + squash the commits first, by requesting changes with a pull request review. +* Does the PR pass the integration tests? Not all checkers have integration + tests, and not all tests are run on CI, so contributors should make sure to + run them on their side. +* Should the PR warrant a line in the changelog? User-facing changes should be + documented in ``CHANGES.rst``. + +For new features: + +* Does the PR include tests? A new syntax checker should have at least one + accompanying integration test. +* Does the PR include documentation? New syntax checkers or options should be + documented in :ref:`flycheck-languages`. + +If all the points above have been addressed, then go ahead and click that green +button :) + +.. note:: + + We require proper merges for pull requests, to preserve the fact that a + change came from a pull request in the git history and to retain any commit + signatures that may exist. As such you can't squash-merge or rebase-merge + through GitHub's UI. + +.. _flycheck-git-signatures: + +Signatures for commits and tags +------------------------------- + +We sign all release tags as part of our :ref:`flycheck-release-process`. Thus +you need a GPG key pair for Git. Github provides a great guide which helps you +to `generate a key`_ and to `tell Git about your key`_. Please also `add your +key`_ to your Github account. + +We also recommend that you sign all your commits with your key. Again, Github +provides a good guide to `sign commits`_. + +.. seealso:: + + `Signing Your Work`_ + For more information about signing commits and tags take a look at the + section in the Git manual. + +.. _Signing Your Work: https://git-scm.com/book/uz/v2/Git-Tools-Signing-Your-Work +.. _generate a key: https://help.github.com/articles/generating-a-gpg-key/ +.. _tell Git about your key: https://help.github.com/articles/telling-git-about-your-gpg-key/ +.. _add your key: https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/ +.. _sign commits: https://help.github.com/articles/signing-commits-using-gpg/ + +Tooling and Services +==================== + +In addition to Github_ where we host code and do code reviews we use a bit of +extra tooling and some 3rd party services for Flycheck: + +* ReadTheDocs_ hosts http://www.flycheck.org and automatically rebuilds it on + every change. It works mostly automatically and requires little + configuration. +* `Travis CI`_ runs our tests after every push and for every pull request. + It's configured through ``.travis.yml``. +* `CLA assistant`_ checks signatures to our CLA_ and allows contributors to sign + the CLA through their Github account. + +All :ref:`maintainers ` have administrative access to +these services so in case of an issue just contact them. + +.. _Github: https://github.com/flycheck +.. _ReadTheDocs: https://readthedocs.org/projects/flycheck/ +.. _Travis CI: https://travis-ci.org/flycheck/flycheck +.. _CLA assistant: https://cla-assistant.io +.. _CLA: https://gist.github.com/lunaryorn/c9c0d656fe7e704da2f734779242ec99 + +.. _flycheck-maintenance-scripts: + +Maintenance scripts +=================== + +Administrative processes are tedious and time-consuming, so we try to automate +as much as possible. The :file:`maint/` directory contains many scripts for +this purpose. ``make -C maint/ help`` provides an overview over all +administrative tasks. + +Most of these scripts require Python 3.5 and additional Python libraries. On OS +X it is recommended that you use Homebrew_ to install the latest Python version +with ``brew install python3``. On Linux you should be able to obtain Python 3.5 +from the package manager of your distribution. + +To install all required libraries run ``make -C maint init``. We recommend that +you use virtualenv_ to avoid a global installation of Python modules. ``make +init`` will warn you if you do not. + +.. _Homebrew: https://brew.sh +.. _virtualenv: https://virtualenv.pypa.io/en/latest/ + +Versioning and releases +======================= + +We use a single continuously increasing version number for Flycheck. + +.. important:: + + Breaking changes may occur **at any point**. + +Please feel free to make a release whenever you think it’s appropriate. +It’s generally a good idea to release when + +- you fixed an important bug that affects many users, +- there are a couple of new syntax checkers available, +- there’s a major new feature in ``master``, +- etc. + +In doubt just make a release. We aim to release early and frequently. If +anything breaks anything we can just publish another release afterwards. + +.. _flycheck-release-process: + +Release process +--------------- + +First, check that + +1. you are on ``master``, +2. your working directory is clean, i.e. has no uncommitted changes or untracked + files, +3. all commits are pushed, +4. and Travis CI passes for the latest commit on ``master``. + +If all is good a new release is a simple as + +.. code-block:: console + + $ make -C maint release + +This runs the release script in :file:`maint/release.py`. If any of the above +requirements isn't met the release script will signal an error and abort. + +The release script bumps the version number, commits and tags a new release, and +pushes it to Github. + +.. note:: + + The tag is *signed*; you must configure Git for :ref:`signing commits and + tags ` before you make a release the first time. + After pushing the new release to Github, the script bumps the version number + again, to the next snapshot, and commits the changes again. + +Once the script is completed please + +1. Edit the `release information`_ on Github and add a short summary about the + release. Don’t forget to add a link to the complete changelog and upload the + package TAR file. +2. Enable the new release on the ReadTheDocs `versions dashboard`_. +3. Announce the new release in our Gitter_ channel, and wherever else you see + fit. + +.. _release information: https://github.com/flycheck/flycheck/releases +.. _versions dashboard: https://readthedocs.org/dashboard/flycheck/versions/ +.. _Gitter: https://gitter.im/flycheck/flycheck + +New maintainers +=============== + +To propose a new maintainer open a pull request that adds the user to +``MAINTAINERS`` and ``doc/community/people.rst``. The pull request is subject +to the :ref:`same rules ` as all other pull +requests. Notably it goes through the same approval process. + +Once merged please also + +- add the new maintainer to the ``Maintainers`` team of the Github + organisation. This does not award additional privileges, it's just to support + ``@flycheck/maintainers`` mentions for the sake of convenience, +- invite the new maintainer to the internal `Maintainers channel`_ on Gitter, + +.. _Maintainers channel: https://gitter.im/flycheck/maintainers diff --git a/doc/contributor/style-guide.rst b/doc/contributor/style-guide.rst new file mode 100644 index 0000000..74f388d --- /dev/null +++ b/doc/contributor/style-guide.rst @@ -0,0 +1,193 @@ +.. _flycheck-style-guide: + +============= + Style Guide +============= + +This document describes our code style. It tells you what to look for when +making changes to Flycheck, or when reviewing pull requests. + +Features +======== + +Flycheck’s scope and focus is providing the infrastructure and foundations for +on-the-fly syntax checking. Flycheck provides the basics but deep integration +with particular programming languages is best left to :ref:`separate packages +`. + +Whether a feature is within the scope of Flycheck is the :ref:`maintainer’s +` judgement call. Generally we reserve the right to +reject any pull request for being out of scope. + +* Avoid a *disproportionate amount of code* for a single syntax checker or + language. Look at the built-in checkers for judgement. A syntax checker that + requires a lot more code than any built-in checker is likely to be rejected. + +* Avoid *deep integration* with a particular UI or completion framework. Emacs’ + standard is our standard: We will reject code that is tied to Helm or Counsel. + +* Likewise do not deviate from Emacs’ default behaviour too much. Stick to + Emacs’ standard for key bindings, interactive functions, etc. + +Backward compatibility +====================== + +Checkers and languages evolve over time, and their error format often change as +a consequence. It is not a goal of Flycheck to work with every version of every +checker ever supported. However, the latest Flycheck version *should always +work* with the contemporary version of a checker. + +As a rule of thumb, if maintaining backward compatibility is trivial (i.e., does +not incur code maintenance costs), then we should do it. For example, a +slightly more complex parsing regexp is OK, but doing version detection to add a +flag would most likely be too much. + +Keep in mind that users may not have the choice of updating to the latest +version of a checker (e.g., ``gcc`` on Debian-based distributions). On the +other hand, npm or Python packages are usually trivial to update. Making an +extra effort to maintain backward compatibility for these hard-to-update +checkers is reasonable. + +The integration tests that are run on our CI should always reflect the latest +supported version. + +Style +===== + +.. important:: + + ``make check compile`` must pass on Emacs 25 or newer. This command checks + for some formatting issues and compilation errors. + + Run ``make format`` with Emacs 25 to automatically reformat the Emacs Lisp + source files. + +* Generally try to fit into the style of the code you see. + +* Indent with the default indentation rules. + +* Follow the :infonode:`(elisp)Programming Tips` for Emacs Lisp. + +* Whitespace: + + * 80 characters per line. + * Avoid tabs and trailing spaces. + +* Naming: + + * Prefix all variables and functions with the name of the containing library, + i.e. ``flycheck-`` for everything that is in :file:`flycheck.el`. + + * End boolean predicates with ``-p``, i.e. ``flycheck-valid-checker-p``. + +* Avoid macros, and use them for syntax only. + +* Adhere to the :infonode:`(elisp)Key Binding Conventions`. Particularly do not + define keys in Emacs’ reserved keymaps or in the :samp:`C-c {LETTER}` space + for user bindings. + +Libraries +========= + +* Do **not** advise built-in or 3rd party functions and commands. + +* Do **not** redefine built-in or 3rd party functions, unless for compatibility, + but then copy the newer definition verbatim. + +* Do **not** use ``with-eval-after-load`` and similar functions. + +* Dependencies: + + * Use built-in Emacs libraries freely. + * Introduce external dependencies with care. Prefer built-in + libraries. ``dash.el`` is fine, though. + * Avoid dependencies on language-specific libraries. + +* Avoid ``cl-lib``: + + * Prefer ``seq`` over ``dash`` over ``cl-lib``. Use list functions from + ``cl-lib`` only as the very last resort. + * Prefer ``let-alist`` and ``pcase`` over ``cl-destructuring-bind``. + +Tests +===== + +* Add comprehensive buttercup specs for new functions and commands to + :file:`test/specs/`. Check whether the specs fit into an existing spec file, + or add a new file instead. In doubt, use a new file. + +* For new syntax checkers add at least one syntax checker integration test to + :file:`test/flycheck-test.el`. Make sure that the test passes with + :samp:`make LANGUAGE={language} integ`. + +Documentation +============= + +* Add docstrings to all functions and variables. + +* Follow the :infonode:`(elisp)Documentation Tips`. + +* Take care to update our manual: + + * Document new interactive commands and user options in the :ref:`user guide + `. + * Document new syntax checkers and new options for existing syntax checkers in + the :ref:`list of languages `. + * Document new or changed version requirements for syntax checkers in the + :ref:`list of languages `. + * Document changes to our build system and tooling in the :ref:`contributor’s + guide ` or the :ref:`maintainer’s guide + `. + +Commits +======= + +* Make each commit self-contained. + +* Squash trivial fixes into previous commits so that no commit in and by itself + violates this style guide. + +* Write commit messages that adhere to the style illustrated below. + +* In doubt prefer long messages over short messages. Take the time to write a + good message that explains the intention of the change and illustrates + noteworthy aspects of the implementation. + +* If the commit fixes a bug try to reproduce a brief description of the bug in + the message and make sure to mention the corresponding GitHub issue + (e.g. ``Fixes GH-42``). + +Commit message style +-------------------- + +This model commit message illustrates our style:: + + Fix a foo bug + + The first line is the summary, 50 characters or less. Write in the + imperative and in present tense: “Fix bug”, not “fixed bug” or “fixes + bug”. Explain the intend of the change not the actual contents which the + diff already provides + + After the summary more paragraphs with detailed explanations may follow, + wrapped at 72 characters. Separate multiple paragraphs by blank lines. + + You may use simple formatting like *emphasis* or _underline_, but keep + it to a minimum. Commit messages are not in Markdown :) + + Commit messages may reference issues by number, like this: See GH-42. + Please use `GH-` to prefix issue numbers. You may also close issues + like this: Fixes GH-42 and closes GH-42. + +`Git Commit`_ and Magit_ provide Emacs mode for Git commit messages, which helps +you to comply to these guidelines. + +.. seealso:: + + `A Note About Git Commit Messages`_ + Further information about good commit messages, including some motivation + for our rules for commit messages. + +.. _Git Commit: https://github.com/magit/magit/ +.. _Magit: https://github.com/magit/magit/ +.. _A Note About Git Commit Messages: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html diff --git a/doc/developer/developing.rst b/doc/developer/developing.rst new file mode 100644 index 0000000..d440fbe --- /dev/null +++ b/doc/developer/developing.rst @@ -0,0 +1,399 @@ +.. _flycheck-developers-guide: + +================= +Developer's Guide +================= + +So you want to extend Flycheck, but have no idea where to start? This guide +will give you an overview of Flycheck internals, and take you through adding a +syntax checker to Flycheck. + +An overview of Flycheck internals +================================= + +The goal of Flycheck is to display errors from external checker programs +directly in the buffer you are editing. Instead of you manually invoking +``make`` or the compiler for your favorite language, Flycheck takes care of it +for you, collects the errors and displays them right there in the buffer. + +How Flycheck works is rather straightforward. Whenever a syntax check is +started (see :ref:`flycheck-syntax-checks`), the following happens: + +1. First, Flycheck runs the external program as an asynchronous process using + ``start-process``. While this process runs, Flycheck simply accumulates its + output. +2. When the process exits, Flycheck parses its output in order to collect the + errors. The raw output is turned into a list of `flycheck-error` objects + containing, among others, the filename, line, column, message and severity of + the error. +3. Flycheck then filters the collected errors to keep only the relevant ones. + For instance, errors directed at other files than the one you are editing are + discarded. The exact sementics of which errors are relevant is defined in + ``flycheck-relevant-error-p``. +4. Relevant errors are highlighted by Flycheck in the buffer, according to user + preference. By default, each error adds a mark in the fringe at the line it + occurs, and underlines the symbol at the position of the error using + *overlays*. +5. Finally, Flycheck rebuilds the error list buffer. + +Flycheck follows this process for all the :ref:`many different syntax checkers +` that are provided by default. + +.. note:: + + Specifically, the above describes the process of *command checkers*, i.e., + checkers that run external programs. All the checkers defined in + ``flycheck-checkers`` are command checkers, but command checkers are actually + instances of *generic checkers*. Many external packages, such as + ``dafny-mode``, ``fstar-mode``, etc. use generic checkers, which allow you + more flexibility, including running Flycheck with persistent subprocess such + as language servers. See :flyc:`flycheck-ocaml` for an example + of how to use a generic checker. + +.. seealso:: + + :infonode:`(elisp)Asynchronous Processes` + How to run and control asynchronous processes from inside Emacs. + + :infonode:`(elisp)Overlays` + How to add temporary annotations to a buffer. + +.. _adding-a-checker: + +Adding a syntax checker to Flycheck +=================================== + +To add a syntax checker to Flycheck, you need to answer a few questions: + +- How to invoke the checker? What is the name of its program, and what + arguments should Flycheck pass to it? +- How to parse the error messages from the checker output? +- What language (or languages) will the checker be used for? + +For instance, if I were to manually run the Scala compiler ``scalac`` on the +following ``hello.scala`` file: + +.. code-block:: scala + + object { + println("Hello, world") + } + +Here is the output I would get: + +.. code-block:: console + + $ scalac hello.scala + hello.scala:1: error: identifier expected but '{' found. + object { + ^ + one error found + + +The compiler reports one syntax error from the file ``hello.scala``, on line 3, +with severity ``error``, and the rest of the line contains the error message. + +So, if we want to instruct Flycheck to run ``scalac`` on our Scala files, we +need to tell Flycheck to: + +- Invoke ``scalac FILE-NAME`` +- Get errors from output lines of the form: ``file-name:line: error:message`` + +Writing the checker +------------------- + +Once you have answered these questions, you merely have to translate the answers +to Emacs Lisp. Here is the full definition of the ``scala`` checker you can +find in ``flycheck.el``: + +.. code-block:: elisp + + (flycheck-define-checker scala + "A Scala syntax checker using the Scala compiler. + + See URL `https://www.scala-lang.org/'." + :command ("scalac" "-Ystop-after:parser" source) + :error-patterns + ((error line-start (file-name) ":" line ": error: " (message) line-end)) + :modes scala-mode + :next-checkers ((warning . scala-scalastyle))) + +The code is rather self-explanatory; but we'll go through it nonetheless. + +First, we define a checker using `flycheck-define-checker`. Its first argument, +``scala``, is the name of the checker, as a symbol. The name is used to refer +to the checker in the documentation, so it should usually be the name of the +language to check, or the name of the program used to do the checking, or a +combination of both. Here, ``scalac`` is the program, but the checker is named +``scala``. There is another Scala checker using ``scalastyle``, with the name +``scala-scalastyle``. See `flycheck-checkers` for the full list of checker +names defined in Flycheck. + +After the name comes the docstring. This is a documentation string answering +three questions: 1) What language is this checker for? 2) What is the program +used? 3) Where can users get this program? Nothing more. In particular, this +string does *not* include user documentation, which should rather go in the +manual (see :ref:`flycheck-languages`). + +The rest of the arguments are keyword arguments; their order does not matter, +but they are usually given in the fashion above. + +- ``:command`` describes what command to run, and what arguments to pass. Here, + we tell Flycheck to run ``scalac -Ystop-after:parser`` on ``source``. In + Flycheck, we usually want to get error feedback as fast as possible, hence we + will pass any flag that will speed up the invocation of a compiler, even at + the cost of missing out on some errors. Here, we are telling ``scalac`` to + stop after the parsing phase to ensure we are getting syntax errors quickly. + + The ``source`` argument is special: it instructs Flycheck to create a + temporary file containing the content of the current buffer, and to pass that + temporary file as argument to ``scalac``. That way, ``scalac`` can be run on + the content of the buffer, even when the buffer has not been saved. There are + other ways to pass the content of the buffer to the command, e.g., by piping + it through standard input. These special arguments are described in the + docstring of `flycheck-substitute-argument`. + +- ``:error-patterns`` describes how to parse the output, using the `rx` regular + expression syntax. Here, we expect ``scalac`` to return error messages of the + form:: + + file:line: error: message + + This is a common output format for compilers. With the following + ``:error-patterns`` value: + + .. code-block:: elisp + + ((error line-start (file-name) ":" line ": error: " (message) line-end)) + + we tell Flycheck to extract three parts from each line in the output that + matches the pattern: the ``file-name``, the ``line`` number, and the + ``message`` content. These three parts are then used by Flycheck to create a + `flycheck-error` with the ``error`` severity. + +- ``:modes`` is the list of Emacs major modes in which this checker can run. + Here, we want the checker to run only in ``scala-mode`` buffers. + +That's it! This definition alone contains everything Flycheck needs to run +``scalac`` on a Scala buffer and parse its output in order to give error +feedback to the user. + +.. note:: + + ``rx.el`` is a built-in Emacs module for declarative regular expressions. + Look for the documentation of the `rx` function inside Emacs for its usage. + Flycheck extends `rx` with a few constructs like ``line``, ``file-name`` and + ``message``. You can find them the full list in the docstring for + `flycheck-rx-to-string`. + +Registering the checker +----------------------- + +Usually, you'll want to register the checker so that it is eligible for +automatic selection. For that, you just need to add the checker symbol to +`flycheck-checkers`. The order of checkers does matter, as only one checker can +be enabled in a buffer at a time. Usually you want to put the most useful +checker as the first checker for that mode. For instance, here are the +JavaScript checkers provided by Flycheck: + +.. code-block:: console + + javascript-eslint + javascript-jshint + javascript-gjslint + javascript-jscs + javascript-standard + +If a buffer is in ``js-mode``, Flycheck will try first to enable +``javascript-eslint`` before any other JavaScript checker. + +There are other factors governing checker selection in a buffer, namely whether +a checker is disabled by user configuration (see +:ref:`flycheck-disable-checkers`), and whether this checker *can* be enabled +(see the ``:enabled`` property in `flycheck-define-generic-checker`). + +.. seealso:: + + flycheck-get-checker-for-buffer + This is the function that looks through `flycheck-checkers` to find a + valid checker for the buffer. + +Writing more complex checkers +----------------------------- + +Here are two examples of more complex checkers: + +.. code-block:: elisp + + (flycheck-define-checker protobuf-protoc + "A protobuf syntax checker using the protoc compiler. + + See URL `https://developers.google.com/protocol-buffers/'." + :command ("protoc" "--error_format" "gcc" + (eval (concat "--java_out=" (flycheck-temp-dir-system))) + ;; Add the file directory of protobuf path to resolve import directives + (eval (concat "--proto_path=" (file-name-directory (buffer-file-name)))) + source-inplace) + :error-patterns + ((info line-start (file-name) ":" line ":" column + ": note: " (message) line-end) + (error line-start (file-name) ":" line ":" column + ": " (message) line-end) + (error line-start + (message "In file included from") " " (file-name) ":" line ":" + column ":" line-end)) + :modes protobuf-mode + :predicate (lambda () (buffer-file-name))) + +.. code-block:: elisp + + (flycheck-define-checker sh-shellcheck + "A shell script syntax and style checker using Shellcheck. + + See URL `https://github.com/koalaman/shellcheck/'." + :command ("shellcheck" + "--format" "checkstyle" + "--shell" (eval (symbol-name sh-shell)) + (option-flag "--external-sources" + flycheck-shellcheck-follow-sources) + (option "--exclude" flycheck-shellcheck-excluded-warnings list + flycheck-option-comma-separated-list) + "-") + :standard-input t + :modes sh-mode + :error-parser flycheck-parse-checkstyle + :error-filter (lambda (errors) + (flycheck-remove-error-file-names "-" errors)) + :predicate (lambda () (memq sh-shell '(bash ksh88 sh))) + :verify + (lambda (_) + (let ((supported (memq sh-shell '(bash ksh88 sh)))) + (list (flycheck-verification-result-new + :label (format "Shell %s supported" sh-shell) + :message (if supported "yes" "no") + :face (if supports-shell 'success '(bold warning)))))) + :error-explainer + (lambda (err) + (let ((error-code (flycheck-error-id err)) + (url "https://github.com/koalaman/shellcheck/wiki/%S")) + (and error-code `(url . ,(format url error-code)))))) + +The ``:command`` forms are longer, as the checkers pass more flags to ``protoc`` +and ``shellcheck``. Note the use of ``eval``, ``option``, and ``option-flag`` +for transforming Flycheck checker options into flags for the command. See the +docstring for `flycheck-substitute-argument` for more info, and look at other +checkers for examples. + +The ``shellcheck`` checker does no use ``source`` nor ``source-inplace``: +instead, it passes the buffer contents on standard input, using +``:standard-input t``. + +The ``protoc`` checker has three patterns in ``:error-patterns``; the first one +will catch ``notes`` from the compiler and turn them into `flycheck-error` +objects with the ``info`` severity; the second is for errors from the file being +checked, and the third one is for errors from other files. In the +``shellcheck`` checker, on the other hand, ``:error-parser`` replaces +``:error-patterns``: ``shellcheck`` outputs results in the standard CheckStyle +XML format, so the definition above uses Flycheck's built-in CheckStyle parser, +and an ``:error-filter`` to replace ``-`` by the current buffer's filename. + +Both checkers use a new ``:predicate`` property to determine when the checker +can be called. In addition to the ``:mode`` property which restricts the +``protoc`` checker to buffers in ``protobuf-mode``, the ``:predicate`` property +ensures that ``protoc`` is called only when there is a file associated to the +buffer (this is necessary since we are passing the file associated to the buffer +``protobuf`` using ``source-inplace`` in ``:command``; in contrast, the +``shellcheck`` checker can run in all buffers, because it sends buffer contents +through a pipe). The second checker has a more complex ``:predicate`` to make +sure that the current shell dialect is supported, and a ``:verify`` function to +help users diagnose configuration issues ( ``:verify`` is helpful for giving +feedback to users; its output gets included when users invoke +`flycheck-verify-setup`) + +Finally, the ``shellcheck`` checker includes an error explainer, which opens the +relevant page on the ShellCheck wiki when users run +`flycheck-explain-error-at-point`. + +There are other useful properties, depending on your situation. Most important +is ``:enabled``, which is like ``:predicate`` but is run only once; it is used +to make sure a checker has everything it needs before being allowed to run in a +buffer (this is particularly useful when the checks are costly: running an +external program and parsing its output, checking for a plugin, etc.). + +.. seealso:: + + flycheck-define-generic-checker + For the full documentation of all the properties you can pass to + `flycheck-define-checker`. Look also in the docstring for + `flycheck-define-command-checker` for additional properties. + +.. note:: + + Don't be afraid to look into the ``flycheck.el`` code. The existing checkers + serve as useful examples you can draw from, and all core functions are + documented. + +Sharing your checker +-------------------- + +Once you have written your own syntax checker, why not `submit a pull request +`__ to integrate it into Flycheck? +If it's useful to you, it may be useful for someone else! Please do check out +our :ref:`flycheck-contributors-guide` to learn how we deal with pull requests. + +Issues with auto-quoting in `flycheck-define-checker` +----------------------------------------------------- + +You may have noticed that lists passed to the ``:command`` or +``:error-patterns`` in the snippets above are not quoted. That is because +`flycheck-define-checker` is a macro which automatically quotes these arguments +(not unlike ``use-package`` and other configuration macros). + +While this makes for less noisy syntax, it unfortunately prevents you from +defining a checker with compile-time arguments. For example, you may be tempted +to have a custom checker in your Emacs configuration written like this: + +.. code-block:: elisp + + (flycheck-define-checker my-foobar-checker + :command ("foobar" source) + :error-patterns ((error …)) + :modes `(foobar-mode ,my-other-foobar-mode)) + +The idea is that you know statically one mode that you want to use the checker +in: ``foobar-mode``, but another mode can be given via the variable +``my-other-foobar-mode`` before the checker is defined. This won't work, +because the ``:modes`` property is auto-quoted by `flycheck-define-checker`. +The issue arises not just with ``:modes``:, but with almost all the other +properties since they are also auto-quoted. + +If you do find yourself in need to define such a checker, there is a solution +though. The `flycheck-define-checker` macro is just a convenience over +`flycheck-define-command-checker`, so you could define the checker above as +follows: + +.. code-block:: elisp + + (flycheck-def-executable-var my-foobar-checker "foobar") + (flycheck-define-command-checker 'my-foobar-checker + :command '("foobar" source) + :error-patterns '((error …)) + :modes `(foobar-mode ,my-other-foobar-mode)) + +Using `flycheck-define-command-checker`, you now need to quote all the list +arguments, but now with the confidence that no auto-quoting will take place, +since `flycheck-define-command-checker` is just a function. Also note that you +need to explicitly define the executable variable for the checker. Using +`flycheck-define-command-checker` is the recommended way to define a checker +with compile-time arguments. + +.. note:: + + The `flycheck-define-checker` macro is an autoload, so using it inside a + `with-eval-after-load` form will load all of Flycheck. While this ensures + the macro is correctly expanded, it also defeats the purpose of using + `with-eval-after-load`. + + For the background behind this state of affairs, see `issue 1398`_. + + .. _issue 1398: https://github.com/flycheck/flycheck/issues/1398 diff --git a/doc/elisp.py b/doc/elisp.py new file mode 100644 index 0000000..1a96b12 --- /dev/null +++ b/doc/elisp.py @@ -0,0 +1,433 @@ +# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +# This file is not part of GNU Emacs. + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + + +from collections import namedtuple +from sphinx import addnodes +from sphinx.util import ws_re +from sphinx.roles import XRefRole +from sphinx.domains import Domain, ObjType +from sphinx.util.nodes import make_refnode +from sphinx.directives import ObjectDescription + + +def make_target(cell, name): + """Create a target name from ``cell`` and ``name``. + + ``cell`` is the name of a symbol cell, and ``name`` is a symbol name, both + as strings. + + The target names are used as cross-reference targets for Sphinx. + + """ + return '{cell}-{name}'.format(cell=cell, name=name) + + +def to_mode_name(symbol_name): + """Convert ``symbol_name`` to a mode name. + + Split at ``-`` and titlecase each part. + + """ + return ' '.join(p.title() for p in symbol_name.split('-')) + + +class Cell(namedtuple('Cell', 'objtype docname')): + """A cell in a symbol. + + A cell holds the object type and the document name of the description for + the cell. + + Cell objects are used within symbol entries in the domain data. + + """ + + pass + + +class KeySequence(namedtuple('KeySequence', 'keys')): + """A key sequence.""" + + PREFIX_KEYS = {'C-u'} + PREFIX_KEYS.update('M-{}'.format(n) for n in range(10)) + + @classmethod + def fromstring(cls, s): + return cls(s.split()) + + @property + def command_name(self): + """The command name in this key sequence. + + Return ``None`` for key sequences that are no command invocations with + ``M-x``. + + """ + try: + return self.keys[self.keys.index('M-x') + 1] + except ValueError: + return None + + @property + def has_prefix(self): + """Whether this key sequence has a prefix.""" + return self.keys[0] in self.PREFIX_KEYS + + def __str__(self): + return ' '.join(self.keys) + + +class EmacsLispSymbol(ObjectDescription): + """An abstract base class for directives documenting symbols. + + Provide target and index generation and registration of documented symbols + within the domain data. + + Deriving classes must have a ``cell`` attribute which refers to the cell + the documentation goes in, and a ``label`` attribute which provides a + human-readable name for what is documented, used in the index entry. + + """ + + cell_for_objtype = { + 'defcustom': 'variable', + 'defconst': 'variable', + 'defvar': 'variable', + 'defface': 'face' + } + + @property + def cell(self): + """The cell in which to store symbol metadata.""" + return self.cell_for_objtype[self.objtype] + + @property + def label(self): + """The label for the documented object type.""" + return self.objtype + + def handle_signature(self, signature, signode): + """Create nodes in ``signode`` for the ``signature``. + + ``signode`` is a docutils node to which to add the nodes, and + ``signature`` is the symbol name. + + Add the object type label before the symbol name and return + ``signature``. + + """ + label = self.label + ' ' + signode += addnodes.desc_annotation(label, label) + signode += addnodes.desc_name(signature, signature) + return signature + + def _add_index(self, name, target): + index_text = '{name}; {label}'.format( + name=name, label=self.label) + self.indexnode['entries'].append( + ('pair', index_text, target, '', None)) + + def _add_target(self, name, sig, signode): + target = make_target(self.cell, name) + if target not in self.state.document.ids: + signode['names'].append(name) + signode['ids'].append(target) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + + obarray = self.env.domaindata['el']['obarray'] + symbol = obarray.setdefault(name, {}) + if self.cell in symbol: + self.state_machine.reporter.warning( + 'duplicate description of %s %s, ' % (self.objtype, name) + + 'other instance in ' + + self.env.doc2path(symbol[self.cell].docname), + line=self.lineno) + symbol[self.cell] = Cell(self.objtype, self.env.docname) + + return target + + def add_target_and_index(self, name, sig, signode): + target = self._add_target(name, sig, signode) + self._add_index(name, target) + + +class EmacsLispMinorMode(EmacsLispSymbol): + cell = 'function' + label = 'Minor Mode' + + def handle_signature(self, signature, signode): + """Create nodes in ``signode`` for the ``signature``. + + ``signode`` is a docutils node to which to add the nodes, and + ``signature`` is the symbol name. + + Add the object type label before the symbol name and return + ``signature``. + + """ + label = self.label + ' ' + signode += addnodes.desc_annotation(label, label) + signode += addnodes.desc_name(signature, to_mode_name(signature)) + return signature + + def _add_index(self, name, target): + return super()._add_index(to_mode_name(name), target) + + +class EmacsLispFunction(EmacsLispSymbol): + """A directive to document Emacs Lisp functions.""" + + cell_for_objtype = { + 'defun': 'function', + 'defmacro': 'function' + } + + def handle_signature(self, signature, signode): + function_name, *args = ws_re.split(signature) + label = self.label + ' ' + signode += addnodes.desc_annotation(label, label) + signode += addnodes.desc_name(function_name, function_name) + for arg in args: + is_keyword = arg.startswith('&') + node = (addnodes.desc_annotation + if is_keyword + else addnodes.desc_addname) + signode += node(' ' + arg, ' ' + arg) + + return function_name + + +class EmacsLispKey(ObjectDescription): + """A directive to document interactive commands via their bindings.""" + + label = 'Interactive command' + + def handle_signature(self, signature, signode): + """Create nodes to ``signode`` for ``signature``. + + ``signode`` is a docutils node to which to add the nodes, and + ``signature`` is the symbol name. + """ + key_sequence = KeySequence.fromstring(signature) + signode += addnodes.desc_name(signature, str(key_sequence)) + return str(key_sequence) + + def _add_command_target_and_index(self, name, sig, signode): + target_name = make_target('function', name) + if target_name not in self.state.document.ids: + signode['names'].append(name) + signode['ids'].append(target_name) + self.state.document.note_explicit_target(signode) + + obarray = self.env.domaindata['el']['obarray'] + symbol = obarray.setdefault(name, {}) + if 'function' in symbol: + self.state_machine.reporter.warning( + 'duplicate description of %s %s, ' % (self.objtype, name) + + 'other instance in ' + + self.env.doc2path(symbol['function'].docname), + line=self.lineno) + symbol['function'] = Cell(self.objtype, self.env.docname) + + index_text = '{name}; {label}'.format(name=name, label=self.label) + self.indexnode['entries'].append( + ('pair', index_text, target_name, '', None)) + + def _add_binding_target_and_index(self, binding, sig, signode): + reftarget = make_target('key', binding) + + if reftarget not in self.state.document.ids: + signode['names'].append(reftarget) + signode['ids'].append(reftarget) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + + keymap = self.env.domaindata['el']['keymap'] + if binding in keymap: + self.state_machine.reporter.warning( + 'duplicate description of binding %s, ' % binding + + 'other instance in ' + + self.env.doc2path(keymap[binding]), + line=self.lineno) + keymap[binding] = self.env.docname + + index_text = '{name}; key binding'.format(name=binding) + self.indexnode['entries'].append( + ('pair', index_text, reftarget, '', None)) + + def add_target_and_index(self, name, sig, signode): + # If unprefixed M-x command index as function and not as key binding + sequence = KeySequence.fromstring(name) + if sequence.command_name and not sequence.has_prefix: + self._add_command_target_and_index(sequence.command_name, + sig, signode) + else: + self._add_binding_target_and_index(name, sig, signode) + + +class XRefModeRole(XRefRole): + """A role to cross-reference a minor mode. + + Like a normal cross-reference role but appends ``-mode`` to the reference + target and title-cases the symbol name like Emacs does when referring to + modes. + + """ + + fix_parens = False + lowercase = False + + def process_link(self, env, refnode, has_explicit_title, title, target): + refnode['reftype'] = 'minor-mode' + target = target + '-mode' + return (title if has_explicit_title else to_mode_name(target), target) + + +class EmacsLispDomain(Domain): + """A domain to document Emacs Lisp code.""" + + name = 'el' + label = 'Emacs Lisp' + + object_types = { + # TODO: Set search prio for object types + # Types for user-facing options and commands + 'minor-mode': ObjType('minor-mode', 'function', 'mode', + cell='function'), + 'define-key': ObjType('key binding', cell='interactive'), + 'defcustom': ObjType('defcustom', 'defcustom', cell='variable'), + 'defface': ObjType('defface', 'defface', cell='face'), + # Object types for code + 'defun': ObjType('defun', 'defun', cell='function'), + 'defmacro': ObjType('defmacro', 'defmacro', cell='function'), + 'defvar': ObjType('defvar', 'defvar', cell='variable'), + 'defconst': ObjType('defconst', 'defconst', cell='variable') + } + directives = { + 'minor-mode': EmacsLispMinorMode, + 'define-key': EmacsLispKey, + 'defcustom': EmacsLispSymbol, + 'defvar': EmacsLispSymbol, + 'defconst': EmacsLispSymbol, + 'defface': EmacsLispSymbol, + 'defun': EmacsLispFunction, + 'defmacro': EmacsLispFunction + } + roles = { + 'mode': XRefModeRole(), + 'defvar': XRefRole(), + 'defconst': XRefRole(), + 'defcustom': XRefRole(), + 'defface': XRefRole(), + 'defun': XRefRole(), + 'defmacro': XRefRole() + } + + data_version = 1 + initial_data = { + # Our domain data attempts to somewhat mirror the semantics of Emacs + # Lisp, so we have an obarray which holds symbols which in turn have + # function, variable, face, etc. cells, and a keymap which holds the + # documentation for key bindings. + 'obarray': {}, + 'keymap': {} + } + + def clear_doc(self, docname): + """Clear all cells documented ``docname``.""" + for symbol in self.data['obarray'].values(): + for cell in list(symbol.keys()): + if docname == symbol[cell].docname: + del symbol[cell] + for binding in list(self.data['keymap']): + if self.data['keymap'][binding] == docname: + del self.data['keymap'][binding] + + def resolve_xref(self, env, fromdocname, builder, + objtype, target, node, contnode): + """Resolve a cross reference to ``target``.""" + if objtype == 'key': + todocname = self.data['keymap'].get(target) + if not todocname: + return None + reftarget = make_target('key', target) + else: + cell = self.object_types[objtype].attrs['cell'] + symbol = self.data['obarray'].get(target, {}) + if cell not in symbol: + return None + reftarget = make_target(cell, target) + todocname = symbol[cell].docname + + return make_refnode(builder, fromdocname, todocname, + reftarget, contnode, target) + + def resolve_any_xref(self, env, fromdocname, builder, + target, node, contnode): + """Return all possible cross references for ``target``.""" + nodes = ((objtype, self.resolve_xref(env, fromdocname, builder, + objtype, target, node, contnode)) + for objtype in ['key', 'defun', 'defvar', 'defface']) + return [('el:{}'.format(objtype), node) for (objtype, node) in nodes + if node is not None] + + def merge_warn_duplicate(self, objname, our_docname, their_docname): + self.env.warn( + their_docname, + "Duplicate declaration: '{}' also defined in '{}'.\n".format( + objname, their_docname)) + + def merge_keymapdata(self, docnames, our_keymap, their_keymap): + for key, docname in their_keymap.items(): + if docname in docnames: + if key in our_keymap: + our_docname = our_keymap[key] + self.merge_warn_duplicate(key, our_docname, docname) + else: + our_keymap[key] = docname + + def merge_obarraydata(self, docnames, our_obarray, their_obarray): + for objname, their_cells in their_obarray.items(): + our_cells = our_obarray.setdefault(objname, dict()) + for cellname, their_cell in their_cells.items(): + if their_cell.docname in docnames: + our_cell = our_cells.get(cellname) + if our_cell: + self.merge_warn_duplicate(objname, our_cell.docname, + their_cell.docname) + else: + our_cells[cellname] = their_cell + + def merge_domaindata(self, docnames, otherdata): + self.merge_keymapdata(docnames, self.data['keymap'], + otherdata['keymap']) + self.merge_obarraydata(docnames, self.data['obarray'], + otherdata['obarray']) + + def get_objects(self): + """Get all documented symbols for use in the search index.""" + for name, symbol in self.data['obarray'].items(): + for cellname, cell in symbol.items(): + yield (name, name, cell.objtype, cell.docname, + make_target(cellname, name), + self.object_types[cell.objtype].attrs['searchprio']) + + +def setup(app): + app.add_domain(EmacsLispDomain) + return {'version': '0.1', 'parallel_read_safe': True} diff --git a/doc/glossary.rst b/doc/glossary.rst new file mode 100644 index 0000000..489f2cb --- /dev/null +++ b/doc/glossary.rst @@ -0,0 +1,53 @@ +========== + Glossary +========== + +The glossary explains most of the special terms we use in this documentation. +some of these are originally explained in the `Emacs manual`_ or the `Emacs Lisp +reference`_, but we reproduce them here for convenience. + +.. _Emacs manual: https://www.gnu.org/software/emacs/manual/html_node/emacs/index.html +.. _Emacs Lisp reference: https://www.gnu.org/software/emacs/manual/html_node/elisp/index.html + +.. glossary:: + + init file + user init file + Your main Emacs configuration file. It’s typically located in your + :term:`user emacs directory` at :file:`$HOME/.emacs.d/init.el`. Emacs + also looks at :file:`$HOME/.emacs`, but this location is not recommended + anymore. To find out the actual path to your init file of your Emacs + session inspect the value of the variable `user-init-file` with :kbd:`C-h + v user-init-file`. You can visit it directly with :kbd:`M-: (find-file + user-init-file)`. + + .. seealso:: + + :infonode:`(emacs)Init File` + More information about the init file. + + :infonode:`(elisp)Init File` + Programming interface for the init file. + + user emacs directory + The directory for all Emacs related files of the current user, at + :file:`~/.emacs.d/`. Many Emacs packages create data files in this + directory, and it holds the recommended location for the :term:`init file` + at :file:`~/.emacs.d/init.el`. + + registered syntax checker + A syntax checker in `flycheck-checkers`. Flycheck will only use these + syntax checkers when checking buffers automatically. + + verification buffer + A buffer shown by `M-x flycheck-verify-setup`. This buffer contains + information about the Flycheck setup for the current buffer. + + executable option + executable options + Options to override the executables of syntax checkers that run external + commands. They are named :samp:`flycheck-{checker}-executable`, + e.g. ``flycheck-c/c++-clang-executable`` for `c/c++-clang`. + + Flycheck implicit defines these options for all syntax checkers defined + with `flycheck-define-checker`. diff --git a/doc/images/flycheck-annotated.png b/doc/images/flycheck-annotated.png new file mode 100644 index 0000000..f2f055a Binary files /dev/null and b/doc/images/flycheck-annotated.png differ diff --git a/doc/images/flycheck-error-list.png b/doc/images/flycheck-error-list.png new file mode 100644 index 0000000..4a77043 Binary files /dev/null and b/doc/images/flycheck-error-list.png differ diff --git a/doc/images/flycheck-error-reports.png b/doc/images/flycheck-error-reports.png new file mode 100644 index 0000000..f599e92 Binary files /dev/null and b/doc/images/flycheck-error-reports.png differ diff --git a/doc/images/flycheck-menu.png b/doc/images/flycheck-menu.png new file mode 100644 index 0000000..506f1d0 Binary files /dev/null and b/doc/images/flycheck-menu.png differ diff --git a/doc/images/flycheck-mode-line-menu.png b/doc/images/flycheck-mode-line-menu.png new file mode 100644 index 0000000..e2339a5 Binary files /dev/null and b/doc/images/flycheck-mode-line-menu.png differ diff --git a/doc/images/flycheck-verify-buffer.png b/doc/images/flycheck-verify-buffer.png new file mode 100644 index 0000000..b5d0402 Binary files /dev/null and b/doc/images/flycheck-verify-buffer.png differ diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..03f73eb --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,173 @@ +========================================== + Flycheck — Syntax checking for GNU Emacs +========================================== + +**Flycheck** is a modern on-the-fly syntax checking extension for GNU Emacs, +intended as replacement for the older Flymake extension which is part of GNU +Emacs. For a detailed comparison to Flymake see :ref:`flycheck-versus-flymake`. + +It uses various syntax checking and linting tools to :ref:`automatically check +the contents of buffers ` while you type, and reports +warnings and errors directly in the buffer, or in an optional :ref:`error list +`: + +.. image:: images/flycheck-annotated.png + +Out of the box Flycheck supports over :ref:`40 different programming languages +` with more than 80 different syntax checking tools, and +comes with a :ref:`simple interface ` to define new +syntax checkers. + +Many :ref:`3rd party extensions ` provide new syntax +checkers and other features like alternative error displays or mode line +indicators. + +Try out +======= + +Flycheck needs GNU Emacs |min-emacs|, and works best on Unix systems. **Windows +users**, please be aware that Flycheck does not support Windows officially, +although it should mostly work fine on Windows. See :ref:`Windows support +` and watch out for `known Windows issues`_! + +To try Flycheck in your Emacs session install some :ref:`syntax checker tools +` and type the following in your ``*scratch*`` buffer and +run ``M-x eval-buffer``: + +.. code-block:: cl + + (require 'package) + (add-to-list 'package-archives + '("MELPA Stable" . "http://stable.melpa.org/packages/") t) + (package-initialize) + (package-refresh-contents) + + (package-install 'flycheck) + + (global-flycheck-mode) + +*On MacOS* also add the following to :ref:`fix your $PATH environment variable +`: + +.. code-block:: cl + + (package-install 'exec-path-from-shell) + (exec-path-from-shell-initialize) + +For a permanent installation of Flycheck follow the :ref:`Installation +` instructions. For a gentle introduction into Flycheck +features go through :ref:`Quickstart ` guide. + +.. important:: + + If Flycheck fails to run properly or gives you any error messages please take + a look at the :ref:`troubleshooting section ` which + covers some common setup issues and helps you debug and fix problems with + Flycheck. + +.. _`known windows issues`: https://github.com/flycheck/flycheck/labels/arch%3A%20windows%20only + +.. _flycheck-user-guide: + +The User Guide +============== + +The User Guide provides installation and usage help for Flycheck. It starts +with installation instructions and a quick start tutorial and then focuses on an +in-depth references of all parts of Flycheck. + +.. toctree:: + + user/installation + user/quickstart + user/troubleshooting + user/syntax-checks + user/syntax-checkers + user/error-reports + user/error-list + user/error-interaction + user/flycheck-versus-flymake + +.. _flycheck-community-guide: + +The Community Guide +=================== + +The Community Guide provides information about Flycheck’s ecosystem and +community. + +.. toctree:: + + community/conduct + community/extensions + community/get-help + community/people + +.. _flycheck-developer-guide: + +The Developer Guide +=================== + +The Developer Guide shows how extend Flycheck and how to write syntax checkers +for Flycheck. + +.. toctree:: + + developer/developing + +.. _flycheck-contributor-guide: + +The Contributor Guide +===================== + +The Contributor Guide explains how to contribute to Flycheck. + +.. toctree:: + + contributor/contributing + contributor/style-guide + contributor/maintaining + +Indices and Tables +================== + +* :ref:`flycheck-languages` +* :doc:`glossary` +* :doc:`changes` +* :ref:`genindex` +* :ref:`search` + +.. toctree:: + :hidden: + + languages + glossary + changes + +Licensing +========= + +Flycheck is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +Flycheck is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +See :ref:`flycheck-gpl` for a copy of the GNU General Public License. + +You may copy, distribute and/or modify the Flycheck documentation under the +terms of the Creative Commons Attribution-ShareAlike 4.0 International Public +License. See :ref:`flycheck-cc-by-sa` for a copy of the license. + +Permission is granted to copy, distribute and/or modify the Flycheck logo under +the terms of the Creative Commons Attribution-ShareAlike 4.0 International +Public License. See :ref:`flycheck-cc-by-sa` for a copy of the license. + +.. toctree:: + :hidden: + :maxdepth: 2 + + licenses diff --git a/doc/info.py b/doc/info.py new file mode 100644 index 0000000..771fa78 --- /dev/null +++ b/doc/info.py @@ -0,0 +1,192 @@ +# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +# This file is not part of GNU Emacs. + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +import re +from string import Template + +import requests +from docutils import nodes +from sphinx.roles import XRefRole +from sphinx.util import ws_re, logging + +logger = logging.getLogger(__name__) + +# Regular expression object to parse the contents of an Info reference +# role. +INFO_RE = re.compile(r'\A\((?P[^)]+)\)(?P.+)\Z') + + +class InfoNodeXRefRole(XRefRole): + """A role to reference a node in an Info manual.""" + + innernodeclass = nodes.emphasis + + def process_link(self, env, refnode, has_explicit_title, title, target): + """Process the link created by this role. + + Swap node and manual name, to more closely match the look of references + in Texinfo. + + """ + # Normalize whitespace in info node targets + target = ws_re.sub(' ', target) + refnode['has_explicit_title'] = has_explicit_title + if not has_explicit_title: + match = INFO_RE.match(target) + if match: + # Swap title and node to create a title like info does + title = '{0}({1})'.format(match.group('node'), + match.group('manual')) + return title, target + + +def node_encode(char): + if char.isalnum(): + return char + elif char == ' ': + return '-' + else: + return '_00{:02x}'.format(ord(char)) + + +def expand_node_name(node): + """Expand ``node`` for use in HTML. + + ``node`` is the name of a node as string. + + Return a pair ``(filename, anchor)``, where ``filename`` is the base-name + of the corresponding file, sans extension, and ``anchor`` the HTML anchor. + + See + http://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Node-Name-Expansion.html. + + """ + if node == 'Top': + return ('index', 'Top') + else: + normalized = ws_re.sub(' ', node.strip()) + encoded = ''.join(node_encode(c) for c in normalized) + prefix = 'g_t' if not node[0].isalpha() else '' + return (encoded, prefix + encoded) + + +class HTMLXRefDB(object): + """Cross-reference database for Info manuals.""" + + #: URL of the htmlxref database of GNU Texinfo + XREF_URL = 'http://ftpmirror.gnu.org/texinfo/htmlxref.cnf' + + #: Regular expression to parse entries from an xref DB + XREF_RE = re.compile(r""" +^\s* +(?: +(?P[#].*) | +(?P\w+)\s*=\s*(?P\S+) | +(?P\w+)\s*(?Pnode|mono)\s*(?P\S+) +) +\s*$""", re.VERBOSE) + + @classmethod + def parse(cls, htmlxref): + substitutions = {} + manuals = {} + for line in htmlxref.splitlines(): + match = cls.XREF_RE.match(line) + if match: + if match.group('substname'): + url = Template(match.group('substurl')).substitute( + substitutions) + substitutions[match.group('substname')] = url + elif (match.group('manname') + and match.group('mantype') == 'node'): + url = Template(match.group('manurl')).substitute( + substitutions) + manuals[match.group('manname')] = url + return cls(manuals) + + def __init__(self, entries): + """Initialize the HTMLXrefDB object with the provided entries.""" + self.entries = entries + + def resolve(self, manual, node): + manual_url = self.entries.get(manual) + if not manual_url: + return None + else: + filename, anchor = expand_node_name(node) + return manual_url + filename + '.html#' + anchor + + +def update_htmlxref(app): + if not isinstance(getattr(app.env, 'info_htmlxref', None), HTMLXRefDB): + logger.info('fetching Texinfo htmlxref database from {0}... '.format( + HTMLXRefDB.XREF_URL)) + try: + app.env.info_htmlxref = HTMLXRefDB.parse( + requests.get(HTMLXRefDB.XREF_URL).text) + except requests.exceptions.ConnectionError: + logger.warning('Failed to load xref DB. ' + 'Info references will not be resolved') + app.env.info_htmlxref = None + + +def resolve_info_references(app, _env, refnode, contnode): + """Resolve Info references. + + Process all :class:`~sphinx.addnodes.pending_xref` nodes whose ``reftype`` + is ``infonode``. + + Replace the pending reference with a :class:`~docutils.nodes.reference` + node, which references the corresponding web URL, as stored in the database + referred to by :data:`HTMLXREF_URL`. + + """ + if refnode['reftype'] != 'infonode': + return None + + target = ws_re.sub(' ', refnode['reftarget']) + match = INFO_RE.match(target) + if not match: + logger.warning('Invalid info target: {0}'.format(target), + location=(refnode.source, refnode.line)) + return contnode + + manual = match.group('manual') + node = match.group('node') + + xrefdb = app.env.info_htmlxref + if xrefdb: + uri = xrefdb.resolve(manual, node) + if not uri: + message = 'Cannot resolve info manual {0}'.format(manual) + logger.warning(message, location=(refnode.source, refnode.line)) + return contnode + else: + reference = nodes.reference('', '', internal=False, + refuri=uri, reftitle=target) + reference += contnode + return reference + else: + # Without an xref DB we're unable to resolve any info references + return None + + +def setup(app): + app.add_role('infonode', InfoNodeXRefRole()) + app.connect(str('builder-inited'), update_htmlxref) + app.connect(str('missing-reference'), resolve_info_references) + return {'version': '0.1', 'parallel_read_safe': True} diff --git a/doc/languages.rst b/doc/languages.rst new file mode 100644 index 0000000..040320c --- /dev/null +++ b/doc/languages.rst @@ -0,0 +1,1611 @@ +.. _flycheck-languages: + +===================== + Supported Languages +===================== + +This document lists all programming and markup languages which Flycheck +supports. + +.. note:: + + Extensions may provide support for additional languages or add deeper + integration with existing languages. + + Take a look at the :ref:`list of extensions ` to see + what the community can offer to you. + +Each language has one or more syntax checkers whose names follow a convention of +:samp:`{language}-{tool}`. All syntax checkers are listed in the order they +would be applied to a buffer, with all available options. For more information +about a syntax checker open Emacs and use :command:`flycheck-describe-checker` +to view the docstring of the syntax checker. Likewise, you may use +:command:`describe-variable` to read the complete docstring of any option. + +.. supported-language:: Ada + + .. syntax-checker:: ada-gnat + + Check ADA syntax and types with `GNAT`_. + + .. _GNAT: https://www.adacore.com/community/ + + .. defcustom:: flycheck-gnat-args + + A list of additional options. + + .. defcustom:: flycheck-gnat-include-path + + A list of include directories. Relative paths are relative to the path + of the buffer being checked. + + .. defcustom:: flycheck-gnat-language-standard + + The language standard to use as string. + + .. defcustom:: flycheck-gnat-warnings + + A list of additional warnings to enable. Each item is the name of a + warning category to enable. + +.. supported-language:: AsciiDoc + + .. syntax-checker:: asciidoctor + + Check AsciiDoc with the default Asciidoctor_ backend. + + .. _Asciidoctor: http://asciidoctor.org + + .. syntax-checker:: asciidoc + + Check AsciiDoc_ with the standard AsciiDoc processor. + + .. _AsciiDoc: http://www.methods.co.nz/asciidoc + +.. supported-language:: Awk + + .. syntax-checker:: awk-gawk + + Check Awk with gawk_. + + .. _gawk: https://www.gnu.org/software/gawk/manual + +.. supported-language:: Bazel + + .. syntax-checker:: bazel-buildifier + + Check Bazel with buildifier_. + + .. _buildifier: https://github.com/bazelbuild/buildtools + +.. supported-language:: C/C++ + :index_as: C + C++ + + Flycheck checks C and C++ with either `c/c++-clang` or `c/c++-gcc`, and then + with `c/c++-cppcheck`. + + .. syntax-checker:: c/c++-clang + c/c++-gcc + + Check C/C++ for syntax and type errors with Clang_ or GCC_ respectively. + + .. note:: + + `c/c++-gcc` requires GCC 4.4 or newer. + + .. _Clang: http://clang.llvm.org/ + .. _GCC: https://gcc.gnu.org/ + + .. defcustom:: flycheck-clang-args + flycheck-gcc-args + + A list of additional arguments for `c/c++-clang` and `c/c++-gcc` + respectively. + + .. defcustom:: flycheck-clang-blocks + + Whether to enable blocks in `c/c++-clang`. + + .. defcustom:: flycheck-clang-definitions + flycheck-gcc-definitions + + A list of additional preprocessor definitions for `c/c++-clang` and + `c/c++-gcc` respectively. + + .. defcustom:: flycheck-clang-include-path + flycheck-gcc-include-path + + A list of include directories for `c/c++-clang` and `c/c++-gcc` + respectively, relative to the file being checked. + + .. defcustom:: flycheck-clang-includes + flycheck-gcc-includes + + A list of additional include files for `c/c++-clang` and `c/c++-gcc` + respectively, relative to the file being checked. + + .. defcustom:: flycheck-clang-language-standard + flycheck-gcc-language-standard + + The language standard to use in `c/c++-clang` and `c/c++-gcc` + respectively as string, via the ``-std`` option. + + .. defcustom:: flycheck-clang-ms-extensions + + Whether to enable Microsoft extensions to C/C++ in `c/c++-clang`. + + .. defcustom:: flycheck-clang-no-exceptions + flycheck-gcc-no-exceptions + + Whether to disable exceptions in `c/c++-clang` and + `c/c++-gcc` respectively. + + .. defcustom:: flycheck-clang-no-rtti + flycheck-gcc-no-rtti + + Whether to disable RTTI in `c/c++-clang` and `c/c++-gcc` respectively, + via ``-fno-rtti``. + + .. defcustom:: flycheck-clang-standard-library + + The name of the standard library to use for `c/c++-clang`, as string. + + .. defcustom:: flycheck-gcc-openmp + + Whether to enable OpenMP in `c/c++-gcc`. + + .. defcustom:: flycheck-clang-pedantic + flycheck-gcc-pedantic + + Whether to warn about language extensions in `c/c++-clang` and + `c/c++-gcc` respectively. + + .. defcustom:: flycheck-clang-pedantic-errors + flycheck-gcc-pedantic-errors + + Whether to error on language extensions in `c/c++-clang` and + `c/c++-gcc` respectively. + + .. defcustom:: flycheck-clang-warnings + flycheck-gcc-warnings + + A list of additional warnings to enable in `c/c++-clang` and + `c/c++-gcc` respectively. Each item is the name of a warning or + warning category for ``-W``. + + .. syntax-checker:: c/c++-cppcheck + + Check C/C++ for semantic and stylistic issues with cppcheck_. + + .. _cppcheck: http://cppcheck.sourceforge.net/ + + .. defcustom:: flycheck-cppcheck-checks + + A list of enabled checks. Each item is the name of a check for the + ``--enable`` option. + + .. defcustom:: flycheck-cppcheck-inconclusive + + Whether to enable inconclusive checks. These checks may yield more + false positives than normal checks. + + .. note:: + + This option requires cppcheck 1.54 or newer. + + .. defcustom:: flycheck-cppcheck-include-path + + A list of include directories. Relative paths are relative to the file + being checked. + + .. defcustom:: flycheck-cppcheck-standards + + The C, C++ and/or POSIX standards to use via one or more ``--std=`` + arguments. + + .. defcustom:: flycheck-cppcheck-suppressions + + The cppcheck suppressions list to use via one or more ``--suppress=`` + arguments. + + .. defcustom:: flycheck-cppcheck-suppressions-file + + The cppcheck suppressions file to use via the + ``--suppressions-list=`` argument. + +.. supported-language:: CFEngine + + .. syntax-checker:: cfengine + + Check syntax with `CFEngine `_. + +.. supported-language:: Chef + + .. syntax-checker:: chef-foodcritic + + Check style in Chef recipes with `foodcritic `_. + + .. defcustom:: flycheck-foodcritic-tags + + A list of tags to select. + +.. supported-language:: Coffeescript + + Flycheck checks Coffeescript syntax with `coffee` and then lints with + `coffee-coffeelint`. + + .. syntax-checker:: coffee + + Check syntax with the `Coffeescript `_ compiler. + + .. syntax-checker:: coffee-coffeelint + + Lint with `Coffeelint `_. + + .. syntax-checker-config-file:: flycheck-coffeelintrc + +.. supported-language:: Coq + + .. syntax-checker:: coq + + Check and proof with the standard `Coq `_ compiler. + +.. supported-language:: CSS + + .. syntax-checker:: css-csslint + + Check syntax and style with `CSSLint`_. + + .. _CSSLint: https://github.com/CSSLint/csslint + + .. syntax-checker:: css-stylelint + + Syntax-check and lint CSS with stylelint_. + + .. _stylelint: https://stylelint.io + + .. syntax-checker-config-file:: flycheck-stylelintrc + + .. defcustom:: flycheck-stylelint-quiet + + Whether to run stylelint in quiet mode via ``--quiet``. + +.. supported-language:: CUDA C/C++ + :index_as: CUDA + + .. syntax-checker:: cuda-nvcc + + Checks syntax for CUDA C/C++ using the nvcc + `nvcc `_ compiler + bundled in the NVIDIA Toolkit. + + CUDA C/C++ uses whichever system compiler you have configured, gcc/clang + etc, but will sanitise error messages into a standardised format that + can be picked up via flycheck. Corner cases may cause some odd behavior. + + .. defcustom:: flycheck-cuda-language-standard + + The C or C++ Language standard that you want the CUDA compiler to enforce. + + .. defcustom:: flycheck-cuda-includes + + A list of cuda includes. + + .. defcustom:: flycheck-cuda-include-path + + A list of include directories for nvcc. + + .. defcustom:: flycheck-cuda-definitions + + Additional preprocessor definitions for nvcc. Is passed unaltered to both + GPU compiler and underlying C/C++ compiler. + +.. supported-language:: CWL + + .. syntax-checker:: cwl + + Syntax check with (`Schema Salad `_). + + .. defcustom:: flycheck-cwl-schema-path + + A path for the schema file for Common Workflow Language. + +.. supported-language:: D + + .. syntax-checker:: d-dmd + + Check syntax and types with (`DMD `_). + + .. note:: + + This syntax checker requires DMD 2.066 or newer. + + .. defcustom:: flycheck-dmd-include-path + + A list of include directories. + + .. defcustom:: flycheck-dmd-args + + A list of additional arguments. + + .. seealso:: + + :flyc:`flycheck-d-unittest` + Flycheck extension which provides a syntax checker to run D unittests + on the fly and report the results with Flycheck. + +.. supported-language:: Dockerfile + + .. syntax-checker:: dockerfile-hadolint + + Check syntax and code style with hadolint_ + + .. _hadolint: https://github.com/hadolint/hadolint + +.. supported-language:: Elixir + + .. syntax-checker:: elixir-credo + + Check code style with `credo `_ + + .. defcustom:: flycheck-elixir-credo-strict + + When non-nil, run credo in strict mode, via ``--strict``. + +.. supported-language:: Emacs Lisp + + Flycheck checks Emacs Lisp with `emacs-lisp` and then with + `emacs-lisp-checkdoc`. + + .. syntax-checker:: emacs-lisp + + Check syntax with the built-in byte compiler. + + .. defcustom:: flycheck-emacs-lisp-load-path + + The load path as list of strings. Relative directories are expanded + against the `default-directory` of the buffer being checked. + + .. defcustom:: flycheck-emacs-lisp-initialize-packages + + Whether to initialize Emacs' package manager with `package-initialize` + before checking the buffer. If set to :elisp:`auto` (the default), + only initialize the package managers when checking files under + `user-emacs-directory`. + + .. defcustom:: flycheck-emacs-lisp-package-user-dir + + The package directory as string. Has no effect if + `flycheck-emacs-lisp-initialize-packages` is nil. + + .. defcustom:: flycheck-emacs-lisp-check-declare + + If non-nil, also check `declare-function` forms using + `check-declare-file`. + + .. syntax-checker:: emacs-lisp-checkdoc + + Check Emacs Lisp documentation conventions with ``checkdoc``. + + .. seealso:: + + :infonode:`(elisp)Documentation Tips` + Information about documentation conventions for Emacs Lisp. + + :gh:`purcell/flycheck-package` + Flycheck extension which adds a syntax checker to check for violation + of Emacs Lisp library headers and packaging conventions. + + :infonode:`(elisp)Library Headers` + Information about library headers for Emacs Lisp files. + +.. supported-language:: Ember Templates + + .. syntax-checker:: ember-template + + Check your Ember templates with + `ember-template-lint `_ + + .. syntax-checker-config-file:: flycheck-ember-template-lintrc + +.. supported-language:: Erlang + + Flycheck checks Erlang with `erlang-rebar3` in rebar projects and + `erlang` otherwise. + + .. syntax-checker:: erlang + + Check Erlang with the standard `Erlang `_ + compiler. + + .. defcustom:: flycheck-erlang-include-path + + A list of include directories. + + .. defcustom:: flycheck-erlang-library-path + + A list of library directories. + + .. syntax-checker:: erlang-rebar3 + + Check Erlang with the `rebar3 `_ build tool. + + .. defcustom:: flycheck-erlang-rebar3-profile + + The profile to use when compiling, e.g. "default" or "test". + The default value is nil which will use the test profile in test + directories, the eqc profile in eqc directories and the default profile + otherwise. + +.. supported-language:: ERuby + + .. syntax-checker:: eruby-erubis + + Check ERuby with `erubis `_. + + .. syntax-checker:: eruby-ruumba + + Check syntax and lint with `Ruumba `_. + + .. note:: + + This syntax checker requires Ruumba 0.1.7 or newer. + + .. defcustom:: flycheck-ruumba-lint-only + + Whether to suppress warnings about style issues, via the ``--lint`` + option. + + .. syntax-checker-config-file:: flycheck-ruumbarc + +.. supported-language:: Fortran + + .. syntax-checker:: fortran-gfortran + + Check Fortran syntax and type with GFortran_. + + .. _GFortran: https://gcc.gnu.org/onlinedocs/gfortran/ + + .. defcustom:: flycheck-gfortran-args + + A list of additional arguments. + + .. defcustom:: flycheck-gfortran-include-path + + A list of include directories. Relative paths are relative to the file + being checked. + + .. defcustom:: flycheck-gfortran-language-standard + + The language standard to use via the ``-std`` option. + + .. defcustom:: flycheck-gfortran-layout + + The source code layout to use. Set to :elisp:`free` or :elisp:`fixed` + for free or fixed layout respectively, or nil (the default) to let + GFortran automatically determine the layout. + + .. defcustom:: flycheck-gfortran-warnings + + A list of warnings enabled via the ``-W`` option. + +.. supported-language:: Go + + Flycheck checks Go with the following checkers: + + 1. `go-gofmt` + 2. `go-golint` + 3. `go-vet` + 4. `go-build` or `go-test` + 5. `go-errcheck` + 6. `go-unconvert` + 7. `go-staticcheck` + + .. syntax-checker:: go-gofmt + + Check Go syntax with `gofmt `_. + + .. syntax-checker:: go-golint + + Check Go code style with `Golint `_. + + .. syntax-checker:: go-vet + + Check Go for suspicious code with vet_. + + .. defcustom:: flycheck-go-vet-print-functions + + A list of print-like functions to check calls for format string problems. + + .. defcustom:: flycheck-go-build-tags + + A list of build tags. + + .. _vet: https://golang.org/cmd/vet/ + + .. syntax-checker:: go-build + + Check syntax and type with the `Go compiler`_. + + .. note:: + + This syntax checker requires Go 1.6 or newer. + + .. _Go compiler: https://golang.org/cmd/go + + .. defcustom:: flycheck-go-build-install-deps + + Whether to install dependencies while checking with `go-build` or + `go-test` + + .. defcustom:: flycheck-go-build-tags + :noindex: + + See `flycheck-go-build-tags` + + .. syntax-checker:: go-test + + Check syntax and types of Go tests with the `Go compiler`_. + + .. note:: + + This syntax checker requires Go 1.6 or newer. + + .. defcustom:: flycheck-go-build-install-deps + :noindex: + + See `flycheck-go-build-install-deps`. + + .. defcustom:: flycheck-go-build-tags + :noindex: + + See `flycheck-go-build-tags` + + .. syntax-checker:: go-errcheck + + Check for unhandled error returns in Go with errcheck_. + + .. note:: + + This syntax checker requires errcheck build from commit 8515d34 (Aug + 28th, 2015) or newer. + + .. _errcheck: https://github.com/kisielk/errcheck + + .. defcustom:: flycheck-go-build-tags + :noindex: + + See `flycheck-go-build-tags` + + .. syntax-checker:: go-unconvert + + Check for unnecessary type conversions with unconvert_. + + .. _unconvert: https://github.com/mdempsky/unconvert + + .. syntax-checker:: go-staticcheck + + Perform static analysis and code linting with staticcheck_, the successor to megacheck. + + .. defcustom:: flycheck-go-version + + staticcheck_ explicitly supports the last two releases of Go, but + supports targeting older versions. Go versions should be specified + like, "1.6", or, "1.11.4". + + .. _staticcheck: https://staticcheck.io/ + +.. supported-language:: Groovy + + .. syntax-checker:: groovy + + Check syntax using the `Groovy `_ compiler. + +.. supported-language:: Haml + + .. syntax-checker:: haml + + Check syntax with the `Haml `_ compiler. + +.. supported-language:: Handlebars + + .. syntax-checker:: handlebars + + Check syntax with the `Handlebars `_ compiler. + +.. supported-language:: Haskell + + Flycheck checks Haskell with `haskell-stack-ghc` (in Stack projects) or + `haskell-ghc`, and then with `haskell-hlint`. + + .. seealso:: + + :flyc:`flycheck-haskell` + Flycheck extension to configure Flycheck's Haskell checkers from the + metadata, with support for Cabal sandboxes. + + :flyc:`flycheck-hdevtools` + Flycheck extension which adds an alternative syntax checker for GHC + using `hdevtools `_. + + .. syntax-checker:: haskell-stack-ghc + haskell-ghc + + Check syntax and type GHC_. In Stack_ projects invoke GHC through Stack + to bring package dependencies from Stack in. + + .. _GHC: https://www.haskell.org/ghc/ + .. _Stack: https://github.com/commercialhaskell/stack + + .. defcustom:: flycheck-ghc-args + + A list of additional arguments. + + .. defcustom:: flycheck-ghc-no-user-package-database + + Whether to disable the user package database (only for `haskell-ghc`). + + .. defcustom:: flycheck-ghc-stack-use-nix + + Whether to enable Nix support for Stack (only for `haskell-stack-ghc`). + + .. defcustom:: flycheck-ghc-stack-project-file + + Allows to override the default ``stack.yaml`` file for Stack, + via ``--stack-yaml`` (only for `haskell-stack-ghc`). + + .. defcustom:: flycheck-ghc-package-databases + + A list of additional package databases for GHC (only for + `haskell-ghc`). Each item points to a directory containing a package + directory, via ``-package-db``. + + .. defcustom:: flycheck-ghc-search-path + + A list of module directories, via ``-i``. + + .. defcustom:: flycheck-ghc-language-extensions + + A list of language extensions, via ``-X``. + + .. syntax-checker:: haskell-hlint + + Lint with `hlint `_. + + .. defcustom:: flycheck-hlint-args + + A list of additional arguments. + + .. defcustom:: flycheck-hlint-language-extensions + + A list of language extensions to enable. + + .. defcustom:: flycheck-hlint-ignore-rules + + A list of rules to ignore. + + .. defcustom:: flycheck-hlint-hint-packages + + A list of additional hint packages to include. + + .. syntax-checker-config-file:: flycheck-hlintrc + +.. supported-language:: HTML + + .. syntax-checker:: html-tidy + + Check HTML syntax and style with `Tidy HTML5`_. + + .. _Tidy HTML5: https://github.com/htacg/tidy-html5 + + .. syntax-checker-config-file:: flycheck-tidyrc + +.. supported-language:: Javascript + + Flycheck checks Javascript with one of `javascript-eslint` or + `javascript-jshint`. + + Alternatively `javascript-standard` is used instead all of the former ones. + + .. syntax-checker:: javascript-eslint + + Check syntax and lint with `ESLint `_. + + .. note:: + + Flycheck automatically :ref:`disables ` + this syntax checker if eslint cannot find a valid configuration file + for the current buffer. + + .. defcustom:: flycheck-eslint-args + + A list of additional arguments that are passed to eslint. + + .. defcustom:: flycheck-eslint-rules-directories + + A list of directories with custom rules. + + .. syntax-checker:: javascript-jshint + + Check syntax and lint with `JSHint `_. + + .. defcustom:: flycheck-jshint-extract-javascript + + Whether to extract Javascript from HTML before linting. + + .. syntax-checker-config-file:: flycheck-jshintrc + + .. syntax-checker:: javascript-standard + + Check syntax and code style with Standard_ or Semistandard_. + + .. _Standard: https://github.com/standard/standard + .. _Semistandard: https://github.com/Flet/semistandard + +.. supported-language:: JSON + + Flycheck checks JSON with `json-jsonlint`, `json-python-json`, or + `json-jq`. + + .. syntax-checker:: json-jsonlint + + Check JSON with `jsonlint `_. + + .. syntax-checker:: json-python-json + + Check JSON with Python's built-in :py:mod:`json` module. + + .. syntax-checker:: json-jq + + Check JSON with jq_. + + This checker accepts multiple consecutive JSON values in a single input, which is useful for jsonlines data. + + .. _jq: https://stedolan.github.io/jq/ + +.. supported-language:: Jsonnet + + .. syntax-checker:: jsonnet + + Checks `Jsonnet `_ with `jsonnet`. + +.. supported-language:: Less + + .. syntax-checker:: less + + Check syntax with the `Less `_ compiler. + + .. note:: + + This syntax checker requires lessc 1.4 or newer. + + .. syntax-checker:: less-stylelint + + Syntax-check and lint Less with stylelint_. + + .. _stylelint: https://stylelint.io + + .. syntax-checker-config-file:: flycheck-stylelintrc + + .. defcustom:: flycheck-stylelint-quiet + + Whether to run stylelint in quiet mode via ``--quiet``. + +.. supported-language:: LLVM + + .. syntax-checker:: llvm-llc + + Check syntax with `llc `_. + +.. supported-language:: Lua + + Flycheck checks Lua with `lua-luacheck`, falling back to `lua`. + + .. syntax-checker:: lua-luacheck + + Check syntax and lint with Luacheck_. + + .. syntax-checker-config-file:: flycheck-luacheckrc + + .. defcustom:: flycheck-luacheck-standards + + The luacheck standards to use via one or more ``--std`` arguments. + + .. _Luacheck: https://github.com/mpeterv/luacheck + + .. syntax-checker:: lua + + Check syntax with the `Lua compiler `_. + +.. supported-language:: Markdown + + .. syntax-checker:: markdown-markdownlint-cli + + Check Markdown with `markdownlint-cli + `_. + + .. syntax-checker-config-file:: flycheck-markdown-markdownlint-cli-config + + .. syntax-checker:: markdown-mdl + + Check Markdown with `markdownlint `_. + + .. defcustom:: flycheck-markdown-mdl-rules + + A list of enabled rules. + + .. defcustom:: flycheck-markdown-mdl-tags + + A list of enabled rule tags. + + .. syntax-checker-config-file:: flycheck-markdown-mdl-style + +.. supported-language:: Nix + + .. syntax-checker:: nix + + Check Nix with nix-instantiate_. + + .. _nix-instantiate: https://nixos.org/nix/manual/#sec-nix-instantiate + + .. syntax-checker:: nix-linter + + Check Nix with nix-linter_. + + .. _nix-linter: https://github.com/Synthetica9/nix-linter + +.. supported-language:: Opam + + .. syntax-checker:: opam + + Check Opam configuration files with `opam lint`_. + + .. _opam lint: https://opam.ocaml.org/doc/man/opam-lint.html + +.. supported-language:: Perl + + Flycheck checks Perl with `perl` and `perl-perlcritic`. + + .. syntax-checker:: perl + + Check syntax with the `Perl `_ interpreter. + + .. defcustom:: flycheck-perl-include-path + + A list of include directories, relative to the file being checked. + + .. defcustom:: flycheck-perl-module-list + + A list of module names to implicitly use. + + .. syntax-checker:: perl-perlcritic + + Lint and check style with `Perl::Critic`_. + + .. _Perl::Critic: https://metacpan.org/pod/Perl::Critic + + .. defcustom:: flycheck-perlcritic-severity + + The severity level as integer for the ``--severity``. + + .. defcustom:: flycheck-perlcritic-theme + + The theme expression, passed as the ``--theme`` to ``perlcritic``. + + .. syntax-checker-config-file:: flycheck-perlcriticrc + +.. supported-language:: PHP + + Flycheck checks PHP with `php`, `php-phpmd` and `php-phpcs`. + + .. syntax-checker:: php + + Check syntax with `PHP CLI`_ + + .. _PHP CLI: http://php.net/manual/en/features.commandline.php + + .. syntax-checker:: php-phpmd + + Lint with `PHP Mess Detector `_. + + .. defcustom:: flycheck-phpmd-rulesets + + A list of rule sets. Each item is either the name of a default rule + set, or the path to a custom rule set file. + + .. syntax-checker:: php-phpcs + + Check style with `PHP Code Sniffer`_. + + .. note:: + + This syntax checker requires PHP Code Sniffer 2.6 or newer. + + .. _PHP Code Sniffer: http://pear.php.net/package/PHP_CodeSniffer + + .. defcustom:: flycheck-phpcs-standard + + The coding standard, either as name of a built-in standard, or as path + to a standard specification. + +.. supported-language:: Processing + + .. syntax-checker:: processing + + Check syntax using the `Processing `_ compiler. + +.. supported-language:: Protobuf + + .. syntax-checker:: protobuf-protoc + + Check syntax using the protoc_ compiler. + + .. _protoc: https://developers.google.com/protocol-buffers/ + + .. defcustom:: flycheck-protoc-import-path + + A list of directories to resolve import directives. Relative paths are + relative to the path of the buffer being checked. + + .. syntax-checker:: protobuf-prototool + + Lint with `prototool `_. + +.. supported-language:: Pug + + .. syntax-checker:: pug + + Check syntax using the `Pug `_ compiler. + +.. supported-language:: Puppet + + Flycheck checks Puppet with `puppet-parser` and lints with `puppet-lint`. + + .. syntax-checker:: puppet-parser + + Check syntax with the `Puppet `_ compiler. + + .. syntax-checker:: puppet-lint + + Link with `Puppet Lint `_. + + .. defcustom:: flycheck-puppet-lint-disabled-checks + + A list of checks to disable. + + .. syntax-checker-config-file:: flycheck-puppet-lint-rc + +.. supported-language:: Python + + Flycheck checks Python with `python-flake8` or `python-pylint`, and falls + back to `python-pycompile` if neither of those is available. + + All Python checkers are invoked indirectly using ``python -c ...`` (rather + than a direct call to ``flake8`` or ``pylint``) to make it easier to switch + between Python 2 and 3. For example, you can use ``(setq + flycheck-python-pylint-executable "python3")`` to run ``pylint`` using Python + 3, or ``(defvaralias 'flycheck-python-flake8-executable + 'python-shell-interpreter)`` to run ``flake8`` through the executable pointed + to by ``python-shell-interpreter``. + + .. note:: + + If Flycheck complains about a missing Python checker, make sure that the + checker is reachable from ``sys.path``, using e.g. ``python -m pylint``: + often, the issue is that the checker is installed globally but not in the + current virtualenv. Alternatively, you can invoke the checker script + directly, with ``(setq flycheck-python-pylint-executable "pylint")``. + + .. seealso:: + + :gh:`flycheck-pyflakes ` + Flycheck extension which adds a syntax checker using `Pyflakes + `_. + + :gh:`msherry/flycheck-pycheckers` + Flycheck extension which can use multiple checkers simultaneously -- + including pyflakes, pep8, flake8, pylint, and mypy 2/3. + + .. syntax-checker:: python-flake8 + + Check syntax and lint with `flake8 `_. + + .. note:: + + This syntax checker requires flake8 3.0 or newer. + + .. defcustom:: flycheck-flake8-error-level-alist + + An alist mapping Flake8 error IDs to Flycheck error levels. + + .. defcustom:: flycheck-flake8-maximum-complexity + + The maximum McCabe complexity allowed for methods. + + .. defcustom:: flycheck-flake8-maximum-line-length + + The maximum length of lines. + + .. syntax-checker-config-file:: flycheck-flake8rc + + .. syntax-checker:: python-pyright + + Type check python with `pyright `_. + + .. note:: + + This syntax checker requires pyright. + + .. syntax-checker:: python-mypy + + Type check python with `mypy `_. + + .. note:: + + This syntax checker requires mypy 0.580 or newer. + + .. syntax-checker-config-file:: flycheck-python-mypy-config + + .. defcustom:: flycheck-python-mypy-cache-dir + + Directory used to write ``.mypy_cache`` directories. + + Set to ``null-device`` to disable writing cache directories + entirely. + + .. syntax-checker:: python-pylint + + Check syntax and lint with `Pylint `_. + + .. note:: + + This syntax checker requires Pylint 1.0 or newer. + + .. defcustom:: flycheck-pylint-use-symbolic-id + + Whether to report symbolic (e.g. ``no-name-in-module``) or numeric + (e.g. ``E0611``) message identifiers. + + .. syntax-checker-config-file:: flycheck-pylintrc + + .. syntax-checker:: python-pycompile + + Check syntax with Python's byte compiler (see :py:mod:`py_compile`). + +.. supported-language:: R + + .. syntax-checker:: r-lintr + + Check syntax and lint with `lintr `_. + + .. defcustom:: flycheck-lintr-caching + + Whether to enable caching in lintr. On by default; it is not + recommended to disable caching unless it causes actual problems. + + .. defcustom:: flycheck-lintr-linters + + Linters to use as a string with an R expression which selects the + linters to use. + +.. supported-language:: Racket + + .. syntax-checker:: racket + + Check syntax with `raco expand`_ from the ``compiler-lib`` package. + + .. note:: + + This syntax checker needs the ``compiler-lib`` package. + + .. _raco expand: http://docs.racket-lang.org/raco/expand.html + +.. supported-language:: RPM Spec + + .. syntax-checker:: rpm-rpmlint + + Lint with `rpmlint `_. + +.. supported-language:: reStructuredText + + Flycheck checks reStructuredText with `rst-sphinx` in Sphinx_ projects and + with `rst` otherwise. + + .. _Sphinx: http://sphinx-doc.org/ + + .. syntax-checker:: rst-sphinx + + Check documents with Sphinx_. + + .. note:: + + This syntax checker requires Sphinx 1.2 or newer. + + .. defcustom:: flycheck-sphinx-warn-on-missing-references + + Whether to emit warnings for all missing references. + + .. syntax-checker:: rst + + Check documents with `docutils `_. + +.. supported-language:: Ruby + + Flycheck checks Ruby with `ruby-rubocop`, `ruby-reek` and `ruby-rubylint`, + falling back to `ruby` or `ruby-jruby` for basic syntax checking if those + are not available. + + .. syntax-checker:: ruby-rubocop + + Check syntax and lint with `RuboCop `_. + + .. note:: + + This syntax checker requires Rubocop 0.34 or newer. + + .. defcustom:: flycheck-rubocop-lint-only + + Whether to suppress warnings about style issues, via the ``--lint`` + option. + + .. syntax-checker-config-file:: flycheck-rubocoprc + + .. syntax-checker:: ruby-standard + + Check syntax and lint with `Ruby Standard `_. + + .. note:: + + This syntax checker and ruby-rubocop are mutually exclusive, since Standard employs an opinionated rubocop config. + + .. defcustom:: flycheck-rubocop-lint-only + :noindex: + + See `flycheck-rubocop-lint-only`. + + .. syntax-checker-config-file:: flycheck-ruby-standardrc + + .. syntax-checker:: ruby-reek + + Check syntax and lint with reek_. + + .. _Reek: https://github.com/troessner/reek + + .. syntax-checker-config-file:: flycheck-reekrc + + .. note:: + + ``flycheck-reekrc`` defaults to ``nil``, because Reek can find its own + configuration. + + .. syntax-checker:: ruby-rubylint + + Check syntax and lint with ruby-lint_. + + .. note:: + + This syntax checker requires ruby-lint 2.0.2 or newer. + + .. _ruby-lint: http://code.yorickpeterse.com/ruby-lint/latest/ + + .. syntax-checker-config-file:: flycheck-rubylintrc + + .. syntax-checker:: ruby + + Check syntax with the `Ruby `_ interpreter. + + .. syntax-checker:: ruby-jruby + + Check syntax with the `JRuby `_ interpreter. + +.. supported-language:: Rust + + Flycheck checks Rust_ with `rust-cargo` in Cargo projects, or `rust` + otherwise. For Cargo projects, you can also use the clippy_ linter with + `rust-clippy`. + + .. _Rust: https://www.rust-lang.org/ + .. _clippy: https://github.com/rust-lang-nursery/rust-clippy + + .. syntax-checker:: rust-cargo + rust + rust-clippy + + Check syntax and types with the Rust_ compiler. In a Cargo_ project the + compiler is invoked through ``cargo check`` to take Cargo dependencies + into account. + + `rust-clippy` has no configurable options. + + .. note:: + + `rust-cargo` requires Rust 1.17 or newer. + `rust` requires Rust 1.18 or newer. + `rust-clippy` requires the nightly version of Rust. + + .. _Cargo: http://doc.crates.io/index.html + + .. seealso:: + + :flyc:`flycheck-rust` + Flycheck extension to configure Rust syntax checkers according to + the current Cargo_ project. + + .. defcustom:: flycheck-rust-args + + A list of additional arguments that are passed to rustc. This option + is ignored by `rust-cargo`. + + .. defcustom:: flycheck-cargo-check-args + + A list of additional arguments passed to the ``cargo check`` + subcommand. + + .. defcustom:: flycheck-rust-check-tests + + Whether to check test code in Rust. + + .. defcustom:: flycheck-rust-crate-root + + A path to the crate root for the current buffer, or nil if the current + buffer is a crate by itself. + + `rust-cargo` ignores this option as the crate root is given by Cargo. + + .. defcustom:: flycheck-rust-crate-type + + For `rust-cargo`, the target type as a string, one of ``lib``, ``bin``, + ``example``, ``test`` or ``bench``. Can also be nil for projects with + a single target. + + For `rust`, the type of the crate to check, as a string for the + ``--crate-type`` option. + + .. defcustom:: flycheck-rust-binary-name + + The name of the binary to pass to ``cargo check --TARGET-TYPE``, as a + string. + + For `rust-cargo`, always required unless `flycheck-rust-crate-type` is + ``lib`` or nil, in which case it is ignored. + + Ignored by `rust`. + + .. defcustom:: flycheck-rust-features + + List of features to activate during build or check. + + The value of this variable is a list of strings denoting features + that will be activated to build the target to check. Features will + be passed to ``cargo check --features=FEATURES``. + + Empty by default. + + Ignored by `rust`. + + .. defcustom:: flycheck-rust-library-path + + A list of additional library directories. Relative paths are relative + to the buffer being checked. + +.. supported-language:: Sass/SCSS + + Flycheck checks SASS with `sass/scss-sass-lint`, falling back to `sass`, and + SCSS with `scss-lint` or `scss-stylelint` falling back to + `sass/scss-sass-lint` first and then `scss` if neither is available. + + .. syntax-checker:: scss-lint + + Syntax-check and lint SCSS with SCSS-Lint_. + + .. note:: + + This syntax checker requires SCSS-Lint 0.43.2 or newer. + + .. _SCSS-Lint: https://github.com/brigade/scss-lint + + .. syntax-checker-config-file:: flycheck-scss-lintrc + + .. syntax-checker:: sass/scss-sass-lint + + Syntax-check and lint Sass/SCSS with SASS-Lint_. + + .. _SASS-Lint: https://github.com/sasstools/sass-lint + + .. syntax-checker-config-file:: flycheck-sass-lintrc + + .. syntax-checker:: scss-stylelint + + Syntax-check and lint SCSS with stylelint_. + + .. _stylelint: https://stylelint.io + + .. syntax-checker-config-file:: flycheck-stylelintrc + + .. defcustom:: flycheck-stylelint-quiet + + Whether to run stylelint in quiet mode via ``--quiet``. + + .. syntax-checker:: sass + scss + + Check SASS and SCSS respectively with the `SCSS compiler + `_. + + .. defcustom:: flycheck-sass-compass + flycheck-scss-compass + + Whether to enable the Compass CSS framework with ``--compass``. + +.. supported-language:: Scala + + Flycheck checks Scala with `scala` and `scala-scalastyle`. + + .. syntax-checker:: scala + + Check syntax and types with the `Scala `_ + compiler. + + .. note:: + + This syntax checker is fairly primitive. For a better Scala experience + we recommend Ensime_. + + .. _Ensime: http://ensime.github.io/ + + .. syntax-checker:: scala-scalastyle + + Check style with `Scalastyle `_. + + .. syntax-checker-config-file:: flycheck-scalastylerc + + .. important:: + + A configuration file is mandatory for this syntax checker. If + `flycheck-scalastylerc` is not set or the configuration file not found + this syntax checker will not be applied. + +.. supported-language:: Scheme + + Flycheck checks CHICKEN Scheme files with ``csc``. + + .. syntax-checker:: scheme-chicken + + Check syntax with ``csc``, the `CHICKEN Scheme `_ + compiler. + + .. defcustom:: flycheck-scheme-chicken-args + + A list of additional options. + + .. important:: + + `Geiser `_ must be installed and active for + this checker to work. + +.. supported-language:: Shell scripting languages + + Flycheck checks various shell scripting languages: + + * Bash with `sh-bash` and `sh-shellcheck` + * POSIX shell (i.e. :file:`/bin/sh`) with `sh-posix-dash` or `sh-posix-bash` + * Zsh with `sh-zsh` + + .. syntax-checker:: sh-bash + + Check Bash_ syntax. + + .. _Bash: http://www.gnu.org/software/bash/ + + .. defcustom:: flycheck-sh-bash-args + + A list of additional arguments that are passed to bash. + + .. syntax-checker:: sh-posix-dash + + Check POSIX shell syntax with Dash_. + + .. _Dash: http://gondor.apana.org.au/~herbert/dash/ + + .. syntax-checker:: sh-posix-bash + + Check POSIX shell syntax with Bash_. + + .. syntax-checker:: sh-zsh + + Check `Zsh `_ syntax. + + .. syntax-checker:: sh-shellcheck + + Lint Bash and POSIX shell with ShellCheck_. + + .. _ShellCheck: https://github.com/koalaman/shellcheck/ + + .. defcustom:: flycheck-shellcheck-excluded-warnings + + A list of excluded warnings. + + .. defcustom:: flycheck-shellcheck-follow-sources + + Allow shellcheck to read sourced files. + +.. supported-language:: Slim + + .. syntax-checker:: slim + + Check Slim using the `Slim `_ compiler. + + .. syntax-checker:: slim-lint + + Check Slim best practices using the `slim-lint + `_ linter. + +.. supported-language:: SQL + + .. syntax-checker:: sql-sqlint + + Check SQL syntax with `Sqlint `_. + +.. supported-language:: systemd Unit Configuration + + .. syntax-checker:: systemd-analyze + + Check systemd unit configuration file syntax with `systemd-analyze`_. + + .. _systemd-analyze: https://www.freedesktop.org/software/systemd/man/systemd-analyze.html + +.. supported-language:: Tcl + + .. syntax-checker:: tcl-nagelfar + + Check Tcl syntax with `Nagelfar `_. + +.. supported-language:: Terraform + + .. syntax-checker:: terraform + + Check Terraform syntax with `terraform fmt`_ + + .. _terraform fmt: https://www.terraform.io/docs/commands/fmt.html + + .. syntax-checker:: terraform-tflint + + Check Terraform with `tflint `_ + + .. defcustom:: flycheck-tflint-variable-files + + A list of files to resolve terraform variables. Relative paths are + relative to the path of the buffer being checked. + +.. supported-language:: Text + + .. syntax-checker:: proselint + + Check English prose with `Proselint `_. + + .. syntax-checker:: textlint + + Check prose with `textlint `_. + + .. syntax-checker-config-file:: flycheck-textlint-config + + .. defcustom:: flycheck-textlint-plugin-alist + + An alist mapping major modes to textlint plugins. + + Flycheck currently supports the following textlint plugins on NPM: + + * textlint-plugin-rst + * textlint-plugin-html + * textlint-plugin-latex + * textlint-plugin-asciidoctor (as well as other AsciiDoc plugins) + + .. note:: + + textlint plugins need to be installed separately. + +.. supported-language:: TeX/LaTeX + + Flycheck checks TeX and LaTeX with either `tex-chktex` or `tex-lacheck`. + + .. syntax-checker:: tex-chktex + + Check style with `ChkTeX `_. + + .. syntax-checker-config-file:: flycheck-chktexrc + + .. syntax-checker:: tex-lacheck + + Check style with `Lacheck `_. + +.. supported-language:: Texinfo + + .. syntax-checker:: texinfo + + Check syntax with :program:`makeinfo` from Texinfo_. + + .. _Texinfo: http://www.gnu.org/software/texinfo/ + +.. supported-language:: TypeScript + + .. syntax-checker:: typescript-tslint + + Check syntax and style with `TSLint `_. + + .. syntax-checker-config-file:: flycheck-typescript-tslint-config + + .. defcustom:: flycheck-typescript-tslint-rulesdir + + Additional rules directory, for user created rules. + + .. defcustom:: flycheck-tslint-args + + A list of additional arguments that are passed to tslint. + +.. supported-language:: Verilog + + .. syntax-checker:: verilog-verilator + + Check syntax with `Verilator `_. + + .. defcustom:: flycheck-verilator-include-path + + A list of include directories. Relative paths are relative to the file + being checked. + +.. supported-language:: VHDL + + .. syntax-checker:: vhdl-ghdl + + Check syntax with `GHDL `_. + + .. defcustom:: flycheck-ghdl-language-standard + + The language standard to use as string. + + .. defcustom:: flycheck-ghdl-workdir + + The directory to use for the file library. + + .. defcustom:: flycheck-ghdl-ieee-library + + The standard to use for the IEEE library. + +.. supported-language:: XML + + Flycheck checks XML with `xml-xmlstarlet` or `xml-xmllint`. + + .. syntax-checker:: xml-xmlstarlet + + Check syntax with `XMLStarlet `_. + + .. defcustom:: flycheck-xml-xmlstarlet-xsd-path + flycheck-xml-xmllint-xsd-path + + Location of XSD schema to validate against for `xml-xmlstarlet` and + `xml-xmllint` respectively. + + .. syntax-checker:: xml-xmllint + + Check syntax with :program:`xmllint` from Libxml2_. + + .. _Libxml2: http://www.xmlsoft.org/ + +.. supported-language:: YAML + + Flycheck checks YAML with `yaml-jsyaml`, `yaml-ruby` or 'yaml-yamllint'. + + .. syntax-checker:: yaml-jsyaml + + Check syntax with `js-yaml `_. + + .. syntax-checker:: yaml-ruby + + Check syntax with Ruby's YAML parser. + + .. syntax-checker:: yaml-yamllint + + Check syntax with yamllint. + + .. syntax-checker-config-file:: flycheck-yamllintrc diff --git a/doc/licenses.rst b/doc/licenses.rst new file mode 100644 index 0000000..413241b --- /dev/null +++ b/doc/licenses.rst @@ -0,0 +1,17 @@ +=================== + Flycheck licenses +=================== + +.. _flycheck-gpl: + +GNU General Public License 3 +============================ + +.. literalinclude:: ../COPYING + +.. _flycheck-cc-by-sa: + +Creative Commons Attribution-ShareAlike 4.0 International +========================================================= + +.. literalinclude:: COPYING.cc-by-sa diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 0000000..cf3cc93 --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,10 @@ +# Sphinx +Sphinx>=1.6 +# Automatically build documentation on changes +sphinx-autobuild +# Sphinx theme +alabaster>=0.7.8 +# Syntax highlighting +Pygments>=2.1 +# Network access +requests>=2.9 diff --git a/doc/user/error-interaction.rst b/doc/user/error-interaction.rst new file mode 100644 index 0000000..b827b19 --- /dev/null +++ b/doc/user/error-interaction.rst @@ -0,0 +1,199 @@ +====================== + Interact with errors +====================== + +There are a couple of things that you can do with Flycheck errors in a buffer: + +* You can navigate to errors, and go to the next or previous error. +* You can display errors to read their error messages. +* You can put error messages and IDs into the kill ring. + +This section documents the corresponding commands and their customisation +options. + +Navigate errors +=============== + +By default Flycheck hooks into Emacs’ standard error navigation on :kbd:`M-g n` +(`next-error`) and :kbd:`M-g p` (`previous-error`). When :mode:`flycheck` is +enabled these commands will jump to the next and previous Flycheck error +respectively. See :infonode:`(emacs)Compilation Mode` for more information +about these commands. + +This way you don’t need to learn special keybindings to navigate Flycheck +errors; navigation should just work out of the box. + +.. note:: + + Visible compilation buffers such as buffers from ``M-x compile``, ``M-x + grep``, etc. still take *precedence* over Flycheck’s errors. + +The exact behaviour of these error navigation features is very context-dependent +and can be very confusing at times so you can disable this integration: + +.. defcustom:: flycheck-standard-error-navigation + + Whether to integrate Flycheck errors into Emacs’ standard error navigation. + Defaults to ``t``, set to ``nil`` to disable. + + .. important:: + + When changing the value you must disable :mode:`flycheck` and enable it + again for the change to take effect in any buffers where :mode:`flycheck` + is enabled. + +Flycheck provides an independent set of navigation commands which will always +navigate Flycheck errors in the current buffer, regardless of visible +compilation buffers and `flycheck-standard-error-navigation`: + +.. define-key:: C-c ! n + M-x flycheck-next-error + + Jump to the next error. + + With prefix argument jump forwards by as many errors as specified by the + prefix argument, e.g. :kbd:`M-3 C-c ! n` will move to the 3rd error from the + current point. With negative prefix argument move to previous errors + instead. Signal an error if there are no more Flycheck errors. + +.. define-key:: C-c ! p + M-x flycheck-previous-error + + Jump to the previous Flycheck error. + + With prefix argument jump backwards by as many errors as specified by the + prefix argument, e.g. :kbd:`M-3 C-c ! p` will move to the 3rd error before + the current point. With negative prefix argument move to next errors + instead. Signal an error if there are no more Flycheck errors. + +.. define-key:: M-x flycheck-first-error + + Jump to the first Flycheck error. + + With prefix argument, jump forwards to by as many errors as specified by the + prefix argument, e.g. :kbd:`M-3 M-x flycheck-first-error` moves to the 3rd + error from the beginning of the buffer. With negative prefix argument move + to the last error instead. + +By default error navigation jumps to all errors but you can choose to skip over +errors with low levels: + +.. defcustom:: flycheck-navigation-minimum-level + + The minimum levels of errors to consider for navigation. + + If set to an error level only navigate to errors whose level is as least as + severe as this one. If ``nil`` navigate to all errors. + +Display errors +============== + +Whenever you move point to an error location Flycheck automatically displays all +Flycheck errors at point after a short delay which you can customise: + +.. defcustom:: flycheck-display-errors-delay + + The number of seconds to wait before displaying the error at point. Floating + point numbers can express fractions of seconds. + +By default Flycheck shows the error messages in the minibuffer or in a separate +buffer if the minibuffer is too small to hold the whole error message but this +behaviour is entirely customisable: + +.. defcustom:: flycheck-display-errors-function + + A function to display errors. + + The function is given the list of Flycheck errors to display as sole argument + and shall display these errors to the user in some way. + +Flycheck provides two built-in functions for this option: + +.. defun:: flycheck-display-error-messages errors + flycheck-display-error-messages-unless-error-list errors + + Show error messages and IDs in the echo area or in a separate buffer if the + echo area is too small (using `display-message-or-buffer` which see). The + latter only displays errors when the :ref:`error list ` + is not visible. To enable it add the following to your :term:`init file`: + + .. code-block:: elisp + + (setq flycheck-display-errors-function + #'flycheck-display-error-messages-unless-error-list) + +.. seealso:: + + :flyc:`flycheck-pos-tip` + A Flycheck extension to display errors in a GUI popup. + +Additionally Flycheck shows errors in a GUI tooltip whenever you hover an error +location with the mouse pointer. By default the tooltip contains the messages +and IDs of all errors under the pointer, but the contents are customisable: + +.. defcustom:: flycheck-help-echo-function + + A function to create the contents of the tooltip. + + The function is given a list of Flycheck errors to display as sole argument + and shall return a single string to use as the contents of the tooltip. + +Errors from other files +======================= + +Some checkers may return errors from files other than the current buffer (e.g., +`gcc` may complain about errors in included files). These errors appear in the +error list, and are also added on the first line of the current buffer. You can +jump to the incriminating files with `flycheck-previous-error`. + +By default, warnings and info messages from other files are ignored, but you can +customize the minimum level: + +.. defcustom:: flycheck-relevant-error-other-file-minimum-level + + The minimum level errors from other files to consider for inclusion in the + current buffer. + + If set to an error level, only display errors from other files whose error + level is at least as severe as this one. If ``nil``, display all errors from + other files. + +To never show any errors from other files, set +`flycheck-relevant-error-other-file-show` to ``nil``. + +.. defcustom:: flycheck-relevant-error-other-file-show + + Whether to show errors from other files. + +Explain errors +============== + +Flycheck also has the ability to display explanations for errors, provided the +error checker is capable of producing these explanations. Currently, only the +`rust` and `rust-cargo` checkers produce explanations. + +.. define-key:: C-c ! e + M-x flycheck-explain-error-at-point + + Display an explanation for the first explainable error at point. + + +Kill errors +=========== + +You can put errors into the kill ring with `C-c ! w`: + +.. define-key:: C-c ! C-w + M-x flycheck-copy-errors-as-kill + + Copy all messages of the errors at point into the kill ring. + +.. define-key:: C-u C-c ! C-w + C-u M-x flycheck-copy-errors-as-kill + + Like `C-c ! w` but with error IDs. + +.. define-key:: M-0 C-c ! C-w + M-0 M-x flycheck-copy-errors-as-kill + + Like `C-c ! w` but do not copy the error messages but only the error IDs. diff --git a/doc/user/error-list.rst b/doc/user/error-list.rst new file mode 100644 index 0000000..a51c53d --- /dev/null +++ b/doc/user/error-list.rst @@ -0,0 +1,98 @@ +.. _flycheck-error-list: + +================= + List all errors +================= + +You can see all errors in the current buffer in Flycheck’s error list: + +.. image:: /images/flycheck-error-list.png + :align: center + +The key `C-c ! l` pops up the error list: + +.. define-key:: C-c ! l + M-x flycheck-list-errors + M-x list-flycheck-errors + + Pop up a list of errors in the current buffer. + +The error list automatically updates itself after every syntax check and follows +the current buffer: If you switch to different buffer or window it automatically +shows the errors of the now current buffer. The buffer whose errors are shown +in the error list is the *source buffer*. + +Whenever the point is on an error in the *source buffer* the error list +highlights these errors—the green line in the screenshot above. + +Within the error list the following key bindings are available: + +========== ==== +:kbd:`RET` Go to the current error in the source buffer +:kbd:`n` Jump to the next error +:kbd:`p` Jump to the previous error +:kbd:`e` Explain the error +:kbd:`f` Filter the error list by level +:kbd:`F` Remove the filter +:kbd:`S` Sort the error list by the column at point +:kbd:`g` Check the source buffer and update the error list +:kbd:`q` Quit the error list and hide its window +========== ==== + +Filter the list +=============== + +By the default the error list shows all errors but sometimes you'd like to hide +warnings to focus only on real errors. The error list lets you hide all errors +below a certain level with :kbd:`f`. This key prompts for an error level and +will remove all errors of lower levels from the list. The filter is permanent +as long as the error list buffer stays alive or the filter is reset with +:kbd:`F`. + +Sort the list +============= + +You can press :kbd:`S` or click on the column headings to sort the error list by +any of the following columns: + +* Line +* Level +* ID +* Message and checker + +Click twice or press :kbd:`S` repeatedly to flip the sort order from ascending +to descending or vice versa. + +Tune error list display +======================= + +By default the error list buffer pops up like any other buffer. Flycheck does +not enforce special rules on how it's displayed and where it's located in the +frame so essentially the error list pops up at arbitrary places wherever Emacs +can find a window for it. + +However you can tell Emacs to obey certain rules when displaying buffers by +customizing the built-in option `display-buffer-alist`. You can use this option +to make the error list display like similar lists in contemporary IDEs like +VisualStudio, Eclipse, etc. with the following code in your :term:`init file`: + +.. code-block:: elisp + + (add-to-list 'display-buffer-alist + `(,(rx bos "*Flycheck errors*" eos) + (display-buffer-reuse-window + display-buffer-in-side-window) + (side . bottom) + (reusable-frames . visible) + (window-height . 0.33))) + +This display rule tells Emacs to always display the error list at the bottom +side of the frame, occupying a third of the entire height of the frame. + +.. seealso:: + + Shackle_ + An Emacs package which provides an alternative way to control buffer + display + +.. _shackle: https://github.com/wasamasa/shackle diff --git a/doc/user/error-reports.rst b/doc/user/error-reports.rst new file mode 100644 index 0000000..46fbf2c --- /dev/null +++ b/doc/user/error-reports.rst @@ -0,0 +1,317 @@ +======================= + See errors in buffers +======================= + +When a syntax check in the current buffer has finished Flycheck reports the +results of the check in the current buffer in two ways: + +* Highlight errors, warnings, etc. directly in the buffer according to + `flycheck-highlighting-mode` and `flycheck-highlighting-style`. +* Indicate errors, warnings, etc. in the fringe according to + `flycheck-indication-mode`. + +Additionally Flycheck indicates its current state and the number of errors and +warnings in the mode line. + +The following screenshot illustrates how this looks like in the default Emacs +color theme. It shows an info, a warning and an error annotation, from top to +bottom. Please also note the fringe indicators on the left side and the +emphasized mode line indicator in the bottom right corner: + +.. image:: /images/flycheck-error-reports.png + :alt: Flycheck showing info, warning and error annotations + :align: center + +.. note:: + + The colours of fringe icons and the whole appearance of the error highlights + depend on the active color theme. Although red, orange and green or blue + seem to be somewhat standard colours for Flycheck’s annotations across many + popular themes, please take a closer look at your color theme if you’re in + doubt about the meaning of a Flycheck highlight. + +Error levels +============ + +All errors that syntax checkers report have a *level* which tells you the +severity of the error. Flycheck has three built-in levels: + +``error`` + Severe errors like syntax or type errors. + +``warning`` + Potential but not fatal mistakes which you should likely fix nonetheless. + +``info`` + Purely informational messages which inform about notable things in the + current buffer, or provide additional help to fix errors or warnings. + +Each error level has a distinct highlighting and colour which helps you to +identify the severity of each error right in the buffer. + +Error highlights +================ + +Flycheck highlights errors directly in the buffer according to +`flycheck-highlighting-mode` and `flycheck-highlighting-style`. + +Most checkers report a single error position, not a range, so Flycheck typically +needs to guess how far to extend the highlighting: by default, it highlights the +whole symbol at the location reported by the checker, as in the screenshot +above, but you can change that range (or even disable highlighting completely) +using `flycheck-highlighting-mode`. + +.. defcustom:: flycheck-highlighting-mode + + How Flycheck chooses which buffer region to highlight: + + ``nil`` + Do not highlight anything at all. + + ``lines`` + Highlight the whole line and discard any information about the column. + + ``columns`` + Highlight the column of the error if any, otherwise like ``lines``. + + ``symbols`` + Highlight the entire symbol around the error column if any, otherwise like + ``columns``. This is this default. + + ``sexps`` + Highlight the entire expression around the error column if any, otherwise + like ``columns``. + + .. warning:: + + In some major modes ``sexps`` is *very* slow, because discovering + expression boundaries is costly. + + The built-in ``python-mode`` is known to suffer from this issue. + + Be careful when enabling this mode. + +Conversely, when a checker reports a range, Flycheck uses that. + +The style of the highlighting is determined by the value of +`flycheck-highlighting-style`. By default, Flycheck highlights error text with +a face indicating the severity of the error (typically, this face applies a +coloured wavy underline). Instead of faces, however, Flycheck can also indicate +erroneous text by inserting delimiters around it (checkers sometimes report +errors that span a large region of the buffer, making underlines distracting, so +in fact Flycheck only applies a face if the error spans less than 5 lines; this +is achieved using the ``conditional`` style described below). + +.. defcustom:: flycheck-highlighting-style + + How Flycheck highlights error regions. + + ``nil`` + Do not indicate error regions. + + ``level-face`` + Apply a face to erroneous text. + + ``(delimiters BEFORE AFTER)`` + Bracket the error text between ``BEFORE`` and ``AFTER``, which can be + strings, images, etc. Chars are handled specially: they are repeated + twice to form double brackets. + + ``(conditional NLINES S1 S2)`` + Chose between styles ``S1`` and ``S2``: ``S1`` if the error covers up to + ``NLINES``, and ``S2`` otherwise. + +To change the style of the underline or use different colours in the +``level-face`` style, customize the following faces, which are used depending on +the error level: + +.. defface:: flycheck-error + flycheck-warning + flycheck-info + + The highlighting face for ``error``, ``warning`` and ``info`` levels + respectively. + +Delimiters use the same faces as the fringe icons described below, in addition +to the `flycheck-error-delimiter` face; delimited text has the +`flycheck-delimited-error` face, which is empty by default. + +.. defface:: flycheck-error-delimiter + + The face applied to ``BEFORE`` and ``AFTER`` delimiters. + +.. defface:: flycheck-delimited-error + + The face applied to error text in ``delimiters`` style. + +Fringe and margin icons +======================= + +In GUI frames, Flycheck also adds indicators to the fringe—the left or right +border of an Emacs window—to help you identify erroneous lines quickly. +These indicators consist of a rightward-pointing double arrow shape coloured in +the colour of the corresponding error level. By default the arrow is 8 pixels +wide, but a 16 pixels version is used if the fringe is `wide enough +`_. + +.. note:: + + Flycheck extensions can define custom error levels with different fringe + indicators. Furthermore some Emacs distributions like Spacemacs redefine + Flycheck’s error levels to use different indicators. If you're using such a + distribution please take a look at its documentation if you're unsure about + the appearance of Flycheck's indicators. + +You can customise the location of these indicators (left or right fringe) with +`flycheck-indication-mode`, which also lets you turn off these indicators +completely; additionally, you can move these indicators into the margins instead +of the fringes: + +.. defcustom:: flycheck-indication-mode + + How Flycheck indicates errors and warnings in the buffer fringes: + + ``left-fringe`` or ``right-fringe`` + Use the left or right fringe respectively. Fringes can only contain + monochrome bitmaps, so Flycheck draws small pixel-art arrows. + + ``left-margin`` or ``right-margin`` + Use the left or right margin respectively. Margins can support all of + Emacs' rendering facilities, so Flycheck uses the ``»`` character, which + scales with the font size. + + ``nil`` + Do not indicate errors and warnings in the fringe or in the margin. + +By default, Emacs displays fringes, but not margins. With ``left-margin`` and +``right-margin`` indication modes, you will need to enable margins in your +``.emacs``. For example: + +.. code-block:: elisp + + (setq-default left-fringe-width 1 right-fringe-width 8 + left-margin-width 1 right-margin-width 0) + +If you intend to use margins only with Flycheck, consider using +``flycheck-set-indication-mode`` in a hook instead; this function adjusts +margins and fringes for the current buffer. + +.. code-block:: elisp + + (setq-default flycheck-indication-mode 'left-margin) + (add-hook 'flycheck-mode-hook #'flycheck-set-indication-mode) + +That function sets fringes and margins to reasonable (but opinionated) defaults, +according to ``flycheck-indication-mode``. To set your own margin and fringe +widths, use a hook and call ``flycheck-refresh-fringes-and-margins``, like this: + +.. code-block:: elisp + + ;; Show indicators in the left margin + (setq flycheck-indication-mode 'left-margin) + + ;; Adjust margins and fringe widths… + (defun my/set-flycheck-margins () + (setq left-fringe-width 8 right-fringe-width 8 + left-margin-width 1 right-margin-width 0) + (flycheck-refresh-fringes-and-margins)) + + ;; …every time Flycheck is activated in a new buffer + (add-hook 'flycheck-mode-hook #'my/set-flycheck-margins) + +The following faces control the colours of fringe and margin indicators. + +.. defface:: flycheck-fringe-error + flycheck-fringe-warning + flycheck-fringe-info + + The icon faces for ``error``, ``warning`` and ``info`` levels respectively. + +When an error spans multiple lines, Flycheck displays a hatch pattern in the +fringes or vertical dots in the margins to indicate the extent of the error. + +To change the fringe bitmap or the symbol used in the margins, use the function +``flycheck-redefine-standard-error-levels``. + +Mode line +========= + +Like all minor modes Flycheck also has a mode line indicator. You can see it in +the bottom right corner of the above screenshot. By default the indicator shows +Flycheck’s current state via one of the following texts: + ++-------------+----------------------------------------------------------------+ +|``FlyC*`` |Flycheck is checking the buffer currently. | ++-------------+----------------------------------------------------------------+ +|``FlyC`` |There are no errors or warnings in the current buffer. | ++-------------+----------------------------------------------------------------+ +|``FlyC:3/5`` |There are three errors and five warnings in the current buffer. | ++-------------+----------------------------------------------------------------+ +|``FlyC-`` |Flycheck did not find a syntax checker for the current buffer. | +| |Take a look at the :ref:`list of supported languages | +| |` and type `C-c ! v` to see what checkers | +| |are available for the current buffer. | ++-------------+----------------------------------------------------------------+ +|``FlyC!`` |The last syntax check failed. Inspect the ``*Messages*`` buffer| +| |look for error messages, and consider :ref:`reporting a bug | +| |`. | ++-------------+----------------------------------------------------------------+ +|``FlyC?`` |The last syntax check had a dubious result. The definition of a| +| |syntax checker may have a bug. Inspect the ``*Messages*`` | +| |buffer and consider :ref:`reporting a bug | +| |`. | ++-------------+----------------------------------------------------------------+ + +You can entirely customise the mode line indicator with `flycheck-mode-line`: + +.. defcustom:: flycheck-mode-line + + A “mode line construct” for Flycheck’s mode line indicator. + +.. seealso:: + + :infonode:`(elisp)Mode Line Data` + Documentation of mode line constructs. + flycheck-status-emoji_ + A Flycheck extension which puts emojis into Flycheck's mode line + indicator. + :flyc:`flycheck-color-mode-line` + A Flycheck extension which colours the entire mode line according to + Flycheck's status. + +.. _flycheck-status-emoji: https://github.com/liblit/flycheck-status-emoji + +Error thresholds +================ + +To avoid flooding a buffers with excessive highlighting, cluttering the +appearance and slowing down Emacs, Flycheck takes precautions against syntax +checkers that report a large number of errors exceeding +`flycheck-checker-error-threshold`: + +.. defcustom:: flycheck-checker-error-threshold + + The maximum number of errors a syntax checker is allowed to report. + + If a syntax checker reports more errors the error information is + **discarded**. To not run into the same issue again on the next syntax check + the syntax checker is automatically added to `flycheck-disabled-checkers` in + this case to disable it for the next syntax check. + +Clear results +============= + +You can explicitly remove all highlighting and indication and all error +information from a buffer: + +.. define-key:: C-c ! C + M-x flycheck-clear + + Clear all reported errors, all highlighting and all indication icons from the + current buffer. + +.. define-key:: C-u C-c ! C + C-u M-x flycheck-clear + + Like `C-c ! C` but also interrupt any syntax check currently running. Use + this command if you think that Flycheck is stuck. diff --git a/doc/user/flycheck-versus-flymake.rst b/doc/user/flycheck-versus-flymake.rst new file mode 100644 index 0000000..4d8b35c --- /dev/null +++ b/doc/user/flycheck-versus-flymake.rst @@ -0,0 +1,290 @@ +.. _flycheck-versus-flymake: + +========================= + Flycheck versus Flymake +========================= + +This article compares Flycheck to the *built-in* Flymake mode. It does not +consider third-party extensions such as flymake-easy_, but references them at +appropriate places. + +We aim for this comparison to be fair and comprehensive, but it may contain +stale information. Please report any inaccuracy you might find, and feel free +to `edit this page`_ and improve it. + +.. note:: + + This comparison was updated at the time of the Emacs 26.1 release, which + contains an overhaul of Flymake. If you are using Emacs 25.3 or below, you + can still access the comparison between Flycheck and the legacy Flymake + `here`_. + +.. _flymake-easy: https://github.com/purcell/flymake-easy +.. _edit this page: https://github.com/flycheck/flycheck/edit/master/doc/user/flycheck-versus-flymake.rst +.. _here: /en/31/ + +Overview +======== + +This table gives an overview of the differences and similarities between +Flycheck and Flymake. The rest of this page describes each point in more +detail. + ++---------------------------+-----------------------+-----------------------+ +| |Flycheck |Flymake | ++===========================+=======================+=======================+ +|Supports Emacs versions ||min-emacs| |26.1+ | ++---------------------------+-----------------------+-----------------------+ +|Built-in |no |yes | ++---------------------------+-----------------------+-----------------------+ +|`Supported languages`_ |100+ built-in, |10 built-in, | +| |200+ w/ 3rd-party |50+ w/ 3rd party | ++---------------------------+-----------------------+-----------------------+ +|`Automatic syntax |built-in |manual | +|checking`_ | | | ++---------------------------+-----------------------+-----------------------+ +|Check triggers |save, newline, change, |save, newline, change | +| |buffer switch | | ++---------------------------+-----------------------+-----------------------+ +|Asynchronous checking |yes, always |yes, for some modes | ++---------------------------+-----------------------+-----------------------+ +|`Automatic syntax checker |by major mode and |no | +|selection `_ | | | ++---------------------------+-----------------------+-----------------------+ +|`Multiple syntax checkers |yes (configurable |yes (all at once) | +|per buffer`_ |chain) | | ++---------------------------+-----------------------+-----------------------+ +|`Definition of new |single declarative |arbitrary function | +|syntax checkers`_ |macro |[#]_ | ++---------------------------+-----------------------+-----------------------+ +|Configuration debugging |built-in (C-c ! v) |none | ++---------------------------+-----------------------+-----------------------+ +|`Error identifiers`_ |yes |no | ++---------------------------+-----------------------+-----------------------+ +|`Error explanations`_ |yes |no | ++---------------------------+-----------------------+-----------------------+ +|`Error parsing helpers |for regexp, JSON and |none | +|`_ |XML | | ++---------------------------+-----------------------+-----------------------+ +|Fringe icons for errors |yes |yes | ++---------------------------+-----------------------+-----------------------+ +|Error highlighting |faces, brackets, mixed |faces only | ++---------------------------+-----------------------+-----------------------+ +|`Error indicators |fringes (incl HiDPI), |fringes only | +|`_ |margins | | ++---------------------------+-----------------------+-----------------------+ +|`Error message display`_ |tooltip, echo area, |tooltip, echo area | +| |fully customizable | | +| |(e.g. tooltip, popup | | +| |w/ 3rd party packages) | | ++---------------------------+-----------------------+-----------------------+ +|List of all errors |yes; filterable by |yes | +| |error level | | ++---------------------------+-----------------------+-----------------------+ + +Detailed review +=============== + +Relation to Emacs +----------------- + +**Flymake** has been part of GNU Emacs since GNU Emacs 22. As such, +contributions to Flymake are subject to the FSF policies on GNU projects. Most +notably, contributors are required to assign their copyright to the FSF. + +**Flycheck** is not part of GNU Emacs. However, it is free software as well, +and publicly developed on the well-known code hosting platform :gh:`Github +`. Contributing to Flycheck does not require a copyright +assignment, only an explicit agreement that your contributions will be licensed +under the GPL. + +Automatic syntax checking +------------------------- + +**Flymake** is not enabled automatically for supported languages. It must be +enabled for each mode individually, or by, e.g., adding to a hook that enables +it for all ``prog-mode`` buffers. If no backends for the major mode are +available, Flymake will non-intrusively tell you in the modeline. + +**Flycheck** provides a global mode `global-flycheck-mode` which enables syntax +checking in every supported language, where it is safe to do so (remote and +encrypted buffers are excluded by default). + +Syntax checkers +--------------- + +Supported languages +~~~~~~~~~~~~~~~~~~~ + +**Flymake** comes with support for Emacs Lisp, Ruby (``ruby`` for syntax check +and ``rubocop`` for lints), Python and Perl. In addition, backends written for +the legacy Flymake are compatible with the new implementation. + +**Flycheck** provides support for `over 50 languages ` with +over 100 syntax checkers, most of them contributed by the community. + +Definition of new syntax checkers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Flymake** backends are single functions which report diagnostics to a callback +function given as argument. + +**Flycheck** provides a single function `flycheck-define-checker` to define a +new syntax checker. This function uses a declarative syntax which is easy to +understand even for users unfamiliar with Emacs Lisp. In fact, most syntax +checkers in Flycheck were contributed by the community. + +For example, the Perl checker in Flycheck is defined as follows: + +.. code-block:: elisp + + (flycheck-define-checker perl + "A Perl syntax checker using the Perl interpreter. + + See URL `http://www.perl.org'." + :command ("perl" "-w" "-c" source) + :error-patterns + ((error line-start (minimal-match (message)) + " at " (file-name) " line " line + (or "." (and ", " (zero-or-more not-newline))) line-end)) + :modes (perl-mode cperl-mode)) + +The whole process is described in :ref:`adding-a-checker`. + +Customization of syntax checkers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Flymake** does not provide built-in means to customize syntax checkers. +Instead, when defining a new syntax checker the user needs to declare +customization variables explicitly and check their value in the init function. + +**Flycheck** provides built-in functions to add customization variables to +syntax checkers and splice the value of these variables into the argument list +of a syntax checking tool. Many syntax checkers in Flycheck provide +customization variables. For instance, you can customize the enabled warnings +for C with `flycheck-clang-warnings`. Flycheck also tries to automatically find +configuration files for syntax checkers. + +Executables of syntax checkers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Flymake** does not provide built-in means to change the executable of a syntax +checker. + +**Flycheck** defines a variable to set the path of a syntax checker tool for +each defined syntax checker and provides the interactive command +`flycheck-set-checker-executable` to change the executable used in a buffer. +The process used to locate checker configuration files can also be customized +using `flycheck-locate-config-file-functions`, allowing you to store your +personal checker configuration files in your ``.emacs.d`` folder. + +Syntax checker selection +------------------------ + +**Flymake** runs all functions added to the `flymake-diagnostic-functions` hook. + +**Flycheck** uses the major mode and checker-specific predicates to + automatically select a syntax checker. + +Custom predicates +~~~~~~~~~~~~~~~~~ + +**Flymake** may allow for backends to implement custom logic to decide whether +to run the check or not. There are no easily-defined predicate functions. + +**Flycheck** supports custom predicate functions. For instance, Emacs uses +a single major mode for various shell script types (e.g. Bash, Zsh, POSIX Shell, +etc.), so Flycheck additionally uses a custom predicate to look at the value of +the variable `sh-shell` in Sh Mode buffers to determine which shell to use for +syntax checking. + +Manual selection +~~~~~~~~~~~~~~~~ + +**Flymake** users may manually select a specific backend by overriding the value +of the backends list. + +**Flycheck** provides the local variable `flycheck-checker` to explicitly use a +specific syntax checker for a buffer and the command `flycheck-select-checker` +to set this variable interactively. + +Multiple syntax checkers per buffer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Flymake** will use all the backends added to the +`flymake-diagnostic-functions` hook to check a buffer; all backends are started +at the same time, but errors are reported in the buffer as soon as a backend +returns them. Backends can also be written to first report errors for the +visible region of the buffer, and collect errors for hidden regions later. + +**Flycheck** can also apply multiple syntax checkers per buffer, but checkers +run in sequence rather than concurrently. For instance, Flycheck will check PHP +files with PHP CLI first to find syntax errors, then with PHP MessDetector to +additionally find idiomatic and semantic errors, and eventually with PHP +CheckStyle to find stylistic errors. The user will see all errors reported by +all of these tools in the buffer. These checker-chains are configurable (see +:ref:`flycheck-checker-chains`), so it's possible to run an advanced style +checker only if a basic syntax checker returned no errors (this avoids +accumulating too many false positives and improves performance). + +Errors +------ + +Error identifiers +~~~~~~~~~~~~~~~~~ + +**Flymake** does not include special treatment for error identifiers. + +**Flycheck** supports identifiers for different kinds of errors, if a syntax +checker provides these. The identifiers appear in the error list and in error +display, and can be copied independently, for instance for use in an inline +suppression comment or to search the web for a particular kind of error. + +Error explanations +~~~~~~~~~~~~~~~~~~ + +Some **Flycheck** checkers can use error identifiers to provide error +explanations in an help buffer (see `flycheck-explain-error-at-point`). + +.. _margins: + +Error indicators +~~~~~~~~~~~~~~~~ + +Both **Flymake** and **Flycheck** indicate errors in the buffer (using overlays) +and in the fringes. Flycheck includes fringe bitmaps for HiDPI screens, and +also supports displaying indicators in the margins instead of the fringes (this +behavior can be customized using `flycheck-indication-mode`, and +`flycheck-highlighting-mode`). + +Error parsing +~~~~~~~~~~~~~ + +**Flymake** lets backend parse error messages from +tools. There are no built-in helpers for defining error patterns, or for +parsing JSON or XML formats. + +**Flycheck** checkers can use regular expressions as well as custom parsing functions. +The preferred way to define a checker is to use the `rx` syntax, extended with +custom forms for readable error patterns. Flycheck includes some ready-to-use +parsing functions for common output formats, such as Checkstyle XML, or JSON +interleaved with plain text. + +Error message display +~~~~~~~~~~~~~~~~~~~~~ + +**Flymake** shows error messages in a tool tip if the user hovers +the mouse over an error location, or in the echo area if the user navigates to +the error with `flymake-goto-next-error`. + +**Flycheck** shows error message in tool tips as well, and also displays error +messages in the echo area if the point is at an error location. This feature is +fully customizable via `flycheck-display-errors-function`, and several +`extensions ` already provide alternative way to display +errors. + +.. rubric:: Footnotes + +.. [#] `flymake-easy`_ provides a function to define a new syntax checker, which + sets all required variables at once. diff --git a/doc/user/installation.rst b/doc/user/installation.rst new file mode 100644 index 0000000..f876f32 --- /dev/null +++ b/doc/user/installation.rst @@ -0,0 +1,146 @@ +.. _flycheck-installation: + +============== + Installation +============== + +This document gives you detailed instructions and information about installing +Flycheck. + +Prerequisites +============= + +Flycheck needs GNU Emacs |min-emacs| and works best on Unix-like systems like +Linux or macOS. It does not support older releases of GNU Emacs or other +flavours of Emacs (e.g. XEmacs, Aquamacs, etc.). + +.. _flycheck-windows-support: + +Windows support +--------------- + +**Flycheck does not explicitly support Windows**, but tries to maintain Windows +compatibility and should generally work fine on Windows, too. However, we can +neither answer questions about Windows nor fix bugs that only occur on Windows +without the help of active Windows users. Please watch out for `known Windows +issues`_. + +.. _known Windows issues: https://github.com/flycheck/flycheck/labels/arch%3A%20windows%20only + +Syntax checking tools +--------------------- + +Flycheck does not check buffers itself but relies on *external* programs to +check buffers. These programs must be installed separately. Please take a look +at the :ref:`list of supported languages ` to find out what +tools are required for a particular language. + +Many of these programs are available in the package repositories of Linux +distributions or in Homebrew_ for macOS. Others can be installed with standard +package managers such as Rubygems, NPM, Cabal, etc. + +.. important:: + + For a GUI Emacs on MacOS we recommend to install and configure + exec-path-from-shell_ to make Emacs use the proper ``$PATH`` and avoid a + :ref:`common setup issue on MacOS `. + +.. _Homebrew: https://brew.sh +.. _exec-path-from-shell: https://github.com/purcell/exec-path-from-shell + +.. _flycheck-package-installation: + +Package installation +==================== + +We recommend to install Flycheck with Emacs' built-in package manager. Flycheck +is available in the popular `MELPA`_ archive which serves up to date snapshots +of Flycheck's development state. We recommend to read through the +:doc:`changelog ` before every upgrade to check for any breaking +changes that might affect you. + +.. note:: + + The sibling repository `MELPA Stable`_ provides packages for Flycheck + releases. If you prefer to follow the most recent changes use MELPA instead, + but be aware that, while we try to be careful about the stability of the + development snapshots, we may make breaking changes anytime without prior + announcement. + +Unfortunately the MELPA repositories are not available in Emacs by default. You +must explicitly add them to `package-archives` with the following code in your +:term:`init file`: + +.. code-block:: elisp + + (require 'package) + + (add-to-list 'package-archives + '("MELPA Stable" . "https://stable.melpa.org/packages/") t) + (package-initialize) + +This adds MELPA Stable; for MELPA replace ``https://stable.melpa.org`` with +``https://melpa.org`` and change the name accordingly. If you do not know where +your init file is inspect the value of `user-init-file` with :kbd:`C-h v +user-init-file`. + +Once the repository is set up you can install Flycheck from Emacs' package menu +at :kbd:`M-x list-packages`, or directly with :kbd:`M-x package-install RET +flycheck`. + +use-package +----------- + +You may want to take a look at `use-package`_ which provides simple syntax to +declare and configure packages in your init file. Specifically it allows to +automatically install missing packages from package archive when Emacs starts. + +Add the following form to your init file to setup Flycheck with `use-package`_: + +.. code-block:: elisp + + (use-package flycheck + :ensure t + :init (global-flycheck-mode)) + +Then press :kbd:`C-M-x` with point somewhere in this form to install and enable +Flycheck for the current Emacs session. + +.. _flycheck-distribution-packages: + +Distribution packages +--------------------- + +Alternatively some distributions provide binary packages of Flycheck. We +officially support the following distributions: + +* Debian 9 and newer: ``apt-get install elpa-flycheck flycheck-doc`` (the latter + for our manual). The `Debian Emacs addon team`_ provides these packages. + +.. _Debian Emacs addon team: https://pkg-emacsen.alioth.debian.org/ + +.. _flycheck-legacy-installation-methods: + +Legacy installation methods +=========================== + +Some users prefer to install Flycheck with legacy methods such as el-get, Git +submodules, etc that were common before Emacs included a package manager. There +are also many 3rd party packages provided by various package managers. We do +neither support nor endorse any of these: + +.. warning:: + + If you install Flycheck in any way other than :ref:`our official packages + ` you do so **at your own risk**. + +Please beware of breakage, and understand that while we do not actively work +against alternative installation methods we will not make compromises to support +alternative installation methods. We will close issues reported for alternative +installation if we fail to reproduce them with a proper installation of +Flycheck. + +.. _MELPA: https://melpa.org +.. _MELPA Stable: https://stable.melpa.org +.. _Getting Started: https://melpa.org/#/getting-started +.. _use-package: https://github.com/jwiegley/use-package diff --git a/doc/user/quickstart.rst b/doc/user/quickstart.rst new file mode 100644 index 0000000..8b7a831 --- /dev/null +++ b/doc/user/quickstart.rst @@ -0,0 +1,80 @@ +.. _flycheck-quickstart: + +============ + Quickstart +============ + +This page gives a quick introduction into Flycheck and an overview of its most +important features. Before you start here please make sure that Flycheck is +:ref:`installed `. + +Enable Flycheck +=============== + +Now add the following code to your :term:`init file` to permanently enable +syntax checking with Flycheck: + +.. code-block:: elisp + + (add-hook 'after-init-hook #'global-flycheck-mode) + +Install syntax checker programs +=============================== + +Now you need to install syntax checking programs for the languages you'd like to +use Flycheck with. The :ref:`list of supported languages ` +tells you which languages Flycheck supports and what programs it uses. + +For instance, you can install Pylint_ for Python and ESLint_ for Javascript: + +.. code-block:: shell + + $ pip install pylint + $ npm install eslint + +.. _Pylint: https://pylint.org +.. _ESLint: https://eslint.org + +Check syntax in a buffer +======================== + +Now you are ready to use Flycheck in a Python or Javascript buffer. Visit a +Python or Javascript file and check whether your Flycheck setup is complete with +`C-c ! v`. + +If everything is green, Flycheck will now start to check the buffer on the fly +while you are editing. Whenever you make a mistake that eslint or Pylint can +catch, Flycheck will highlight the corresponding place in the buffer with an +error underline whose color reflects the severity of the issue. Additionally, +Flycheck will put a symbol into the fringe for affected lines and show the total +number of errors and warnings in the buffer in the mode line. + +Navigate and list errors +======================== + +With `C-c ! n` and `C-c ! p` you can now jump back and forth between erroneous +places. If you keep on such a place for a little while Flycheck will show the +corresponding error message in the each area. Likewise, if you hover such a +place with the mouse cursor Flycheck will show the error message in a tooltip. + +Press `C-c ! l` to pop up a list of all errors in the current buffer. This list +automatically updates itself when you fix errors or introduce new ones, and +follows the currently selected buffer. If the error list is selected you can +type :kbd:`n` and :kbd:`p` to move up and down between errors and jump to their +corresponding location in the buffer. + +More features +============= + +All Flycheck commands are available in the Emacs Menu at :menuselection:`Tools +---> Syntax checking`: + +.. figure:: /images/flycheck-menu.png + + The menu of Flycheck, showing all available Flycheck commands + +The same menu also pops up when you click on the mode line lighter: + +.. figure:: /images/flycheck-mode-line-menu.png + + The mode line menu of Flycheck diff --git a/doc/user/syntax-checkers.rst b/doc/user/syntax-checkers.rst new file mode 100644 index 0000000..753342c --- /dev/null +++ b/doc/user/syntax-checkers.rst @@ -0,0 +1,330 @@ +================= + Syntax checkers +================= + +Flycheck does not check buffers on its own. Instead it delegates this task to +external *syntax checkers* which are external programs or services that receive +the contents of the current buffer and return a list of errors in the buffer, +together with metadata that tells Flycheck how to run the program, how to pass +buffer contents to it, and how to extract errors. + +.. seealso:: + + :ref:`flycheck-languages` + A complete list of all syntax checkers included in Flycheck + +Like everything else in Emacs syntax checkers have online documentation which +you can access with `C-c ! ?`: + +.. define-key:: C-c ! ? + M-x flycheck-describe-checker + + Prompt for the name of a syntax checker and pop up a Help buffer with its + documentation. + + The documentation includes the name of the program or service used, a list of + major modes the checker supports and a list of all options for this syntax + checker. + +.. _flycheck-automatic-selection: + +Select syntax checkers automatically +==================================== + +Normally Flycheck automatically selects the best syntax checkers for the current +buffer from `flycheck-checkers` whenever it needs to check the buffer: + +.. defcustom:: flycheck-checkers + + A list of all syntax checkers available for syntax checking. + + A syntax checker in this list is a :term:`registered syntax checker`. + +Flycheck picks the first syntax checker from this list which exists and supports +the current major mode, and runs it over the current buffer. When the checker +has finished, Flycheck looks for the next syntax checker to run, and if there is +one, Flycheck runs the next syntax checker, and so on, until there is no more +syntax checker for the current buffer. This process repeats whenever Flycheck +needs to check the buffer according to `flycheck-check-syntax-automatically`. + +.. important:: + + Under some circumstances—for instance if the syntax checker is not installed— + Flycheck automatically :ref:`disables syntax checkers + ` in the current buffer and will thus not even + consider them in any future checks in the current buffer. + + In the `verification buffer ` these syntax checkers are marked as + “disabled” just as if you had disabled them manually with `C-c ! x`, and + likewise you can re-enable automatically disabled syntax checkers with `C-u + C-c ! x`. + +For instance, the first syntax checker for Emacs Lisp is `emacs-lisp` which +checks Emacs Lisp with Emacs' own byte compiler. This syntax checker asks for +`emacs-lisp-checkdoc` to run next, which checks for stylistic issues in Emacs +Lisp docstrings. Thus Flycheck will first run the byte compiler and then +checkdoc in an Emacs Lisp buffer. + +.. _flycheck-manual-selection: + +Select syntax checkers manually +=============================== + +Alternatively you can tell Flycheck explicitly which syntax checker to start +with in the current buffer: + +.. define-key:: C-c ! s + M-x flycheck-select-checker + + Prompt for a syntax checker and use this syntax checker as the first syntax + checker for the current buffer. + + Flycheck may still run further syntax checkers from `flycheck-checkers` if + the selected syntax checker asks for it. + +Flycheck will use the selected syntax checker as “entry point” for syntax checks +in the current buffer, just as if it had selected this syntax checker +automatically. It will automatically run further syntax checkers from +`flycheck-checkers` if the selected syntax checker asks for it. + +Under the hood `C-c ! s` sets `flycheck-checker`: + +.. defvar:: flycheck-checker + + The name of a syntax checker to use for the current buffer. + + If ``nil`` (the default) let Flycheck :ref:`automatically select + ` the best syntax checker from + `flycheck-checkers`. + + If set to a syntax checker Flycheck will use this syntax checker as the first + one in the current buffer, and run subsequent syntax checkers just as if it + had selected this one automatically. + + If the syntax checker in this variable does not work in the current buffer + signal an error. + + This variable is buffer-local. + +We recommend to set `flycheck-checker` via directory local variables to enforce +a specific syntax checker for a project. For instance, Flycheck usually prefers +`javascript-eslint` for Javascript buffers, but if your project uses +`javascript-jshint` instead you can tell Flycheck to use `javascript-jshint` for +all Javascript buffers of your project with the following command in the +top-level directory of your project: :kbd:`M-x add-dir-local-variable RET +js-mode RET flycheck-checker RET javascript-jshint`. A new buffer pops up that +shows the newly created entry in the directory variables. Save this buffer and +kill it. From now on Flycheck will check all Javascript files of this project +with JSHint. + +.. seealso:: + + :infonode:`(emacs)Locals` + General information about local variables. + + :infonode:`(emacs)Directory Variables` + Information about directory variables. + +To go back to automatic selection either set `flycheck-checker` to ``nil`` or +type `C-u C-c ! s`: + +.. define-key:: C-u C-c ! s + C-u M-x flycheck-select-checker + + Remove any selected syntax checker and let Flycheck again :ref:`select a + syntax checker automatically `. + +.. _flycheck-disable-checkers: + +Disable syntax checkers +======================= + +Even if you :ref:`select a checker manually ` +Flycheck may still use a syntax checker that you’d not like to use. To +completely opt out from a specific syntax checker disable it: + +.. define-key:: C-c ! x + M-x flycheck-disable-checker + + Prompt for a syntax checker to disable in the current buffer. + +For instance if you do not care for documentation conventions of Emacs Lisp you +can opt out from `emacs-lisp-checkdoc` which checks your code against these +conventions with :kbd:`C-c ! x emacs-lisp-checkdoc`. After the next check all +checkdoc warnings will be gone from the buffer. + +Internally this command changes the buffer-local `flycheck-disabled-checkers`: + +.. defcustom:: flycheck-disabled-checkers + + A list of disabled syntax checkers. Flycheck will *never* use disabled + syntax checkers to check a buffer. + + This option is buffer-local. You can customise this variable with :kbd:`M-x + customize-variable RET flycheck-disabled-checkers` or set the default value + in your :term:`init file` to permanently disable specific syntax checkers. + For instance: + + .. code-block:: elisp + + (setq-default flycheck-disabled-checkers '(c/c++-clang)) + + will permanently disable `c/c++-clang` in all buffers. + +You can also disable syntax checkers per project with directory local variables. +For instance type :kbd:`M-x add-dir-local-variable RET emacs-lisp-mode RET +flycheck-disabled-checkers RET (emacs-lisp-checkdoc)` in your :term:`user emacs +directory` to disable `emacs-lisp-checkdoc` for all Emacs Lisp files in your +personal configuration. + +.. seealso:: + + :infonode:`(emacs)Locals` + General information about local variables. + + :infonode:`(emacs)Directory Variables` + Information about directory variables. + +To enable a disabled checker again, remove it from `flycheck-disabled-checkers` +or use `C-u C-c ! x`: + +.. define-key:: C-u C-c ! x + C-u M-x flycheck-disable-checker + + Prompt for a disabled syntax checker to enable again in the current buffer. + +.. _flycheck-checker-options: + +Configure syntax checkers +========================= + +Many syntax checkers provide command line flags to change their behaviour. +Flycheck wraps important flags as regular Emacs user options. + +The :ref:`list of supported languages ` includes all options +for each syntax checker. You can change these options in the Customize +interface under :menuselection:`programming --> tools --> flycheck --> +flycheck-options`, however we recommend to use Directory Variables to configure +syntax checkers per project. + +.. seealso:: + + :infonode:`(emacs)Directory Variables` + Information about directory variables. + +.. _flycheck-checker-config-files: + +Configuration files +------------------- + +Some syntax checkers can additionally read configuration from files. Flycheck +can find configuration files of syntax checkers and use them when invoking the +syntax checker program: + +.. defcustom:: flycheck-local-config-file-functions + + Functions to call to find a configuration file for a syntax checker. Each + function gets the name of a configuration file and shall return the absolute + path to a file if one exists. The default value leads to the following + steps: + + 1. If the name is an absolute path, use it. + 2. If the name exists in any ancestor directory, use the nearest one. + 3. If the name exists in ``$HOME``, use it. + + This option is an abnormal hook, see :infonode:`(elisp)Hooks`. + +Flycheck takes the names of configuration files from user options defined for +syntax checkers that support configuration files. Like above the :ref:`list of +languages ` also lists all supported configuration file +options. You can also change these in Customize, under +:menuselection:`programming --> tools --> flycheck --> flycheck-config-files`, +but again we recommend to use Directory Variables. + +We also recommend to prefer configuration files over options as you can usually +commit the configuration files to your source control repository to share them +with other contributors so that all contributors can use the same configuration +for syntax checking and linting. + +.. _flycheck-checker-executables: + +Change syntax checker executables +================================= + +Flycheck normally tries to run syntax checker tools by their standard name from +`exec-path`. Sometimes, though, you need to use a different version of a tool, +or probably don't even have a tool available globally—this frequently occurs in +Javascript project where dependencies including linter tools are typically +installed into a local ``node_modules`` directory: + +.. define-key:: M-x flycheck-set-checker-executable + + Prompt for a syntax checker and an executable file and make Flycheck use the + executable file for the syntax checker in the current buffer. + + Internally this command sets a variable named + :samp:`flycheck-{checker}-executable` where :samp:`{checker}` is the name of + the syntax checker entered on the prompt, e.g. `c/c++-clang`. + + Flycheck defines these :term:`executable options` for every syntax checker + that runs an external command. You can change these variables with directory + variables or set them in custom Emacs Lisp code such as mode hooks. + + .. seealso:: + + :infonode:`(emacs)Directory Variables` + Information about directory variables. + +.. _flycheck-checker-chains: + +Configuring checker chains +========================== + +In any given buffer where Flycheck is enabled, only one checker may be run at a +time. However, any number of checkers can be run in sequence. In such a +sequence, after the first checker has finished running and its errors have been +reported, the next checker of the sequence runs and its errors are reported, +etc. until there are no more checkers in the sequence. This sequence is called +a *checker chain*. + +Some checkers chains are already setup by default in Flycheck: e.g., +`emacs-lisp` will be followed by `emacs-lisp-checkdoc`, and `python-mypy` will +be followed by `python-flake8`. + +When defining a checker, you can specify which checkers may run after it by +setting the ``:next-checkers`` property (see the docstring of +`flycheck-define-generic-checker`). + +For a given checker, several next checkers may be specified. Flycheck will run +the first (in order of declaration) whose error level matches (see below) and +which can be used in the current buffer. + +You can also customize the next checker property by calling +`flycheck-add-next-checker` in your Emacs configuration file. + +.. defun:: flycheck-add-next-checker checker next &optional append + + Set *next* to run after *checker*. Both arguments are syntax checker + symbols. + + For example, the following will make `python-pylint` run after + `python-flake8`: + + .. code-block:: elisp + + (flycheck-add-next-checker 'python-flake8 'python-pylint) + + *Next* may also be a cons cell ``(level . next-checker)``, where + *next-checker* is a symbol denoting the syntax checker to run after + *checker*, and *level* is an error level. The *next-checker* will then only + be run if there is no current error whose level is more severe than *level*. + If *level* is ``t``, then *next-checker* is run regardless of the current + errors. + + For instance, if you wanted to run `python-pylint` only if `python-flake8` + produced no errors (only warnings and info diagnostics), then you would + rather use: + + .. code-block:: elisp + + (flycheck-add-next-checker 'python-flake8 '(warning . python-pylint)) diff --git a/doc/user/syntax-checks.rst b/doc/user/syntax-checks.rst new file mode 100644 index 0000000..9130b92 --- /dev/null +++ b/doc/user/syntax-checks.rst @@ -0,0 +1,145 @@ +.. _flycheck-syntax-checks: + +=============== + Check buffers +=============== + +Flycheck provides two Emacs minor modes for automatic syntax checking: +:mode:`flycheck` to enable syntax checking in the current buffer, and +:mode:`global-flycheck` to enable syntax checking in all buffers whenever +possible. + +.. minor-mode:: flycheck-mode + + Enable :ref:`automatic syntax checking ` in the + current buffer. + +.. minor-mode:: global-flycheck-mode + + Enable :mode:`flycheck` in all buffers where syntax checking is possible. + + .. note:: + + This mode does not enable :mode:`flycheck` in remote files (via + TRAMP) and encrypted files. Checking remote files may be very slow + depending on the network connections, and checking encrypted files would + leak confidential data to temporary files and subprocesses. + + You can manually enable :mode:`flycheck` in these buffers nonetheless, but + we do *not* recommend this for said reasons. + + Add the following to your :term:`init file` to enable syntax checking + permanently: + + .. code-block:: elisp + + (add-hook 'after-init-hook #'global-flycheck-mode) + + You can exclude specific major modes from syntax checking with + `flycheck-global-modes`: + + .. defcustom:: flycheck-global-modes + + Major modes for which :mode:`global-flycheck` turns on :mode:`flycheck`: + + ``t`` (the default) + Turn :mode:`flycheck` on for all major modes. + + :samp:`({foo-mode} …)` + Turn :mode:`flycheck` on for all major modes in this list, + i.e. whenever the value of ``major-mode`` is contained in this list. + + :samp:`(not {foo-mode} …)` + Turn :mode:`flycheck` on for all major nodes *not* in this list, + i.e. whenever the value of ``major-mode`` is *not* contained in this + list. + + .. note:: + + :mode:`global-flycheck` never turns on :mode:`flycheck` in major modes + whose ``mode-class`` property is ``special``, regardless of the value + of this option. Syntax checking simply makes no sense in special + buffers which are typically intended for non-interactive display rather + than editing. + + .. seealso:: + + :infonode:`(elisp)Major Mode Conventions` + Information about major modes, and modes marked as special. + +.. _flycheck-automatic-checks: + +Check automatically +=================== + +By default :mode:`flycheck` automatically checks a buffer whenever + +* it is enabled, +* the buffer is saved, +* a new line is inserted, +* or a short time after the last change was made in a buffer. + +You can customise this behaviour with `flycheck-check-syntax-automatically`: + +.. defcustom:: flycheck-check-syntax-automatically + + A list of events which trigger a syntax check in the current buffer: + + ``save`` + Check the buffer immediately after it was saved. + + ``new-line`` + Check the buffer immediately after a new line was inserted. + + ``idle-change`` + Check the buffer a short time after the last change. The delay is + customisable with `flycheck-idle-change-delay`: + + .. defcustom:: flycheck-idle-change-delay + + Seconds to wait after the last change to the buffer before starting a + syntax check. + + ``idle-buffer-switch`` + Check the buffer a short time after switching to it from another + buffer. The delay is customisable with + `flycheck-idle-buffer-switch-delay`: + + .. defcustom:: flycheck-idle-buffer-switch-delay + + Seconds to wait after switching to a buffer before starting a + syntax check. + + If you switch to several buffers in rapid succession, the + behavior depends on + `flycheck-buffer-switch-check-intermediate-buffers`: + + .. defcustom:: flycheck-buffer-switch-check-intermediate-buffers + + If non-nil, then a buffer you switch to will have a syntax + check run even if you switch to another buffer before it + starts. If nil, then only the current buffer can have a + syntax check run. Note that syntax checks can still be run + in other buffers due to changes to their contents. + + ``mode-enabled`` + Check the buffer immediately after :mode:`flycheck` was enabled. + + For instance with the following setting :mode:`flycheck` will only check the + buffer when it was saved: + + .. code-block:: elisp + + (setq flycheck-check-syntax-automatically '(mode-enabled save)) + +.. _flycheck-manual-checks: + +Check manually +============== + +You can also start a syntax check explicitly with `C-c ! c`: + +.. define-key:: C-c ! c + M-x flycheck-buffer + + Check syntax in the current buffer. diff --git a/doc/user/troubleshooting.rst b/doc/user/troubleshooting.rst new file mode 100644 index 0000000..87f9503 --- /dev/null +++ b/doc/user/troubleshooting.rst @@ -0,0 +1,129 @@ +.. _flycheck-troubleshooting: + +================= + Troubleshooting +================= + +If syntax checking does not work as expected there are a number of steps that +you can follow to isolate and maybe fix the problem. + +.. _flycheck-common-issues: + +Common issues +============= + +First check whether your issue is one of the common setup issues and problems. + +.. _flycheck-macos-exec-path-from-shell: + +Flycheck can’t find any programs in GUI Emacs on MacOS +------------------------------------------------------ + +Try to install and configure exec-path-from-shell_ to make a GUI Emacs inherit +the ``$PATH`` environment variable from your shell configuration. + +The issue is that due to the special way MacOS starts GUI programs a GUI Emacs +does not inherit the environment variables from the shell configuration so Emacs +will lack some important entries in ``$PATH``, most notably ``/usr/local/bin/`` +where Homebrew, NPM and many other package managers put binaries in. + +The `exec-path-from-shell`_ works around this issue by extracting environment +variables from a shell session and inject them into the environment of the +running Emacs instance. + +.. _exec-path-from-shell: https://github.com/purcell/exec-path-from-shell + +Flycheck warns about “non-zero exit code, but no errors” +-------------------------------------------------------- + +Make sure that you have the latest version of the syntax checker installed, +particularly if the message started appearing after you updated Flycheck. + +Newer releases of Flycheck may require newer versions of syntax checking tools. +For instance Flycheck might now pass a command line flag that older versions do +not understand, or attempt to parse an updated output format. In these cases +the syntax checker will show an error message about an unknown flag, or emit +output that Flycheck does not understand, which prompts Flycheck to warn that +even though the syntax checker appeared to not have successfully checked the +buffer content there are no errors to be found. + +If you *are* using the latest version then this message most likely indicates a +flaw in the syntax checker definition. In this case please :ref:`report a bug +` to us so that we can fix the issue. Please don’t forget +to say that you are using the latest version! + +Verify your setup +================= + +If your issue is none of the aforementioned :ref:`common issues +` the first step is to let Flycheck check your setup: + +.. define-key:: C-c ! v + M-x flycheck-verify-setup + + Show a :term:`verification buffer` with information about your + :mode:`flycheck` setup for the current buffer. + + The buffer contains all syntax checkers available for the current buffer and + tells you whether Flycheck would use each one and what reasons would prevent + Flycheck from using a checker. It also includes information about your + Flycheck and Emacs version and your operating system. + +The following image shows a :term:`verification buffer`: + +.. image:: /images/flycheck-verify-buffer.png + +The buffer shows all syntax checkers for the current buffer. Note that you can +click on the syntax checker names to show the docstring for a syntax checker. + +* *Green* items indicate *good* configuration. In the screenshot both + `python-flake8` and `python-pycompile` exist. + +* *Orange* items indicate a *potential* misconfiguration. The screenshot shows + that no configuration file was found for `python-flake8` which is perfectly + fine if there’s no flake8 configuration file in the project, but not so good + if you’d like Flycheck to use a configuration file for flake8. The section + :ref:`flycheck-checker-config-files` has more information about configuration + files. + + Likewise the buffer warns you that a ``demo`` syntax checker (which is not + part of Flycheck of course) isn’t registered in `flycheck-checkers`. If you’d + like Flycheck to automatically use this syntax checker you should fix this + issue by adding it to `flycheck-checkers` but otherwise it’s safe to ignore + this warning. + +* *Red* items indicate *bad* configuration. `python-pylint` wasn’t found in the + screenshot, so you’ll not be able to use pylint in the current buffer. + +Debug syntax checkers +===================== + +If a syntax checker fails although it successfully verified you need to take a +closer look. Flycheck provides you with a command that lets you run a single +syntax checker just the way Flycheck would run it: + +.. define-key:: C-c ! C-c + M-x flycheck-compile + + Prompt for a syntax checker and run in as a shell command, showing the whole + output in a separate buffer. + + .. important:: + + The current implementation this command suffers from a couple of issues, + so we’d like to have a replacement in GH-854_ and we could use your help! + If you’d like to help out with this task please join the discussion in + that issue. + + .. _GH-854: https://github.com/flycheck/flycheck/issues/854 + +The output of this command can provide you helpful clues about what’s going on. +It also helps to compare the output of the command in Emacs with what happens if +you run the same command in a terminal. + +If all else fails… +================== + +…please do :ref:`ask for help `. We have many different +channels, from Twitter to a chat room to StackOverflow, whatever suits you best, +and we try to help you as fast and as well as possible. diff --git a/flycheck-buttercup.el b/flycheck-buttercup.el new file mode 100644 index 0000000..9802265 --- /dev/null +++ b/flycheck-buttercup.el @@ -0,0 +1,157 @@ +;;; flycheck-buttercup.el --- Flycheck: Extensions to Buttercup -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Flycheck contributors +;; Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; Maintainer: Clément Pit-Claudel +;; fmdkdd +;; Keywords: lisp, tools + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Extensions to Buttercup to write BDD tests for Flycheck. +;; +;; Buttercup is a BDD testing framework for Emacs, see URL +;; `https://github.com/jorgenschaefer/emacs-buttercup/'. Flycheck uses +;; Buttercup extensively for new tests. +;; +;; This library provides extensions to Buttercup to write Specs for Flycheck. +;; +;; * Custom matchers +;; +;; (expect 'foo :to-be-local) - Is `foo' a local variable in the current buffer? + +;;; Code: + +(require 'buttercup) +(require 'flycheck) +(require 'seq) + + +;;; Buttercup helpers + +(defun flycheck-buttercup-format-error-list (errors) + "Format ERRORS into a human-readable string." + (mapconcat (lambda (e) (flycheck-error-format e 'with-file-name)) + errors "\n")) + + +;;; Data matchers + +(buttercup-define-matcher :to-be-empty-string (s) + (let ((s (funcall s))) + (if (equal s "") + (cons t (format "Expected %S not be an empty string" s)) + (cons nil (format "Expected %S to be an empty string" s))))) + +(buttercup-define-matcher :to-match-with-group (re s index match) + (let* ((re (funcall re)) + (s (funcall s)) + (index (funcall index)) + (match (funcall match)) + (matches? (string-match re s)) + (result (and matches? (match-string index s)))) + (if (and matches? (equal result match)) + (cons t (format "Expected %S not to match %S with %S in group %s" + re s match index)) + + (cons nil (format "Expected %S to match %S with %S in group %s, %s" + re s match index + (if matches? + (format "but got %S" result) + "but did not match")))))) + + +;;; Emacs feature matchers + +(buttercup-define-matcher :to-be-live (buffer) + (let ((buffer (get-buffer (funcall buffer)))) + (if (buffer-live-p buffer) + (cons t (format "Expected %S not to be a live buffer, but it is" + buffer)) + (cons nil (format "Expected %S to be a live buffer, but it is not" + buffer))))) + +(buttercup-define-matcher :to-be-visible (buffer) + (let ((buffer (get-buffer (funcall buffer)))) + (cond + ((and buffer (get-buffer-window buffer)) + (cons t (format "Expected %S not to be a visible buffer, but it is" + buffer))) + ((not (bufferp buffer)) + (cons nil + (format "Expected %S to be a visible buffer, but it is not a buffer" + buffer))) + (t (cons + nil + (format "Expected %S to be a visible buffer, but it is not visible" + buffer)))))) + +(buttercup-define-matcher :to-be-local (symbol) + (let ((symbol (funcall symbol))) + (if (local-variable-p symbol) + (cons t (format "Expected %S not to be a local variable, but it is" + symbol)) + (cons nil (format "Expected %S to be a local variable, but it is not" + symbol))))) + +(buttercup-define-matcher :to-contain-match (buffer re) + (let ((buffer (funcall buffer)) + (re (funcall re))) + (if (not (get-buffer buffer)) + (cons nil (format "Expected %S to contain a match of %s, \ +but is not a buffer" buffer re)) + (with-current-buffer buffer + (save-excursion + (goto-char (point-min)) + (if (re-search-forward re nil 'noerror) + (cons t (format "Expected %S to contain a match \ +for %s, but it did not" buffer re)) + (cons nil (format "Expected %S not to contain a match for \ +%s but it did not." buffer re)))))))) + + +;;; Flycheck matchers + +(buttercup-define-matcher :to-be-equal-flycheck-errors (a b) + (let* ((a (funcall a)) + (b (funcall b)) + (a-formatted (flycheck-buttercup-format-error-list a)) + (b-formatted (flycheck-buttercup-format-error-list b))) + (if (equal a b) + (cons t (format "Expected +%s +not to be equal to +%s" a-formatted b-formatted)) + (cons nil (format "Expected +%s +to be equal to +%s" a-formatted b-formatted))))) + +(provide 'flycheck-buttercup) + +;; Disable byte compilation for this library, to prevent package.el choking on a +;; missing `buttercup' library. See +;; https://github.com/flycheck/flycheck/issues/860 + +;; Local Variables: +;; no-byte-compile: t +;; End: + +;;; flycheck-buttercup.el ends here diff --git a/flycheck-ert.el b/flycheck-ert.el new file mode 100644 index 0000000..4d64a73 --- /dev/null +++ b/flycheck-ert.el @@ -0,0 +1,507 @@ +;;; flycheck-ert.el --- Flycheck: ERT extensions -*- lexical-binding: t; -*- + +;; Copyright (C) 2017-2018 Flycheck contributors +;; Copyright (C) 2013-2016 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; Maintainer: Clément Pit-Claudel +;; fmdkdd +;; URL: https://github.com/flycheck/flycheck + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Unit testing library for Flycheck, the modern on-the-fly syntax checking +;; extension for GNU Emacs. + +;; Provide various utility functions and unit test helpers to test Flycheck and +;; Flycheck extensions. + +;;; Code: + +(require 'flycheck) +(require 'ert) +(require 'macroexp) ; For macro utilities + + +;;; Compatibility + +(eval-and-compile + ;; Provide `ert-skip' and friends for Emacs 24.3 + (defconst flycheck-ert-ert-can-skip (fboundp 'ert-skip) + "Whether ERT supports test skipping.") + + (unless (fboundp 'define-error) + ;; from Emacs `subr.el' + (defun define-error (name message &optional parent) + "Define NAME as a new error signal. +MESSAGE is a string that will be output to the echo area if such an error +is signaled without being caught by a `condition-case'. +PARENT is either a signal or a list of signals from which it inherits. +Defaults to `error'." + (unless parent (setq parent 'error)) + (let ((conditions + (if (consp parent) + (apply #'append + (mapcar + (lambda (parent) + (cons parent + (or (get parent 'error-conditions) + (error "Unknown signal `%s'" parent)))) + parent)) + (cons parent (get parent 'error-conditions))))) + (put name 'error-conditions + (delete-dups (copy-sequence (cons name conditions)))) + (when message (put name 'error-message message))))) + + (unless flycheck-ert-ert-can-skip + ;; Fake skipping + + (define-error 'flycheck-ert-skipped "Test skipped") + + (defun ert-skip (data) + (signal 'flycheck-ert-skipped data)) + + (defmacro skip-unless (form) + `(unless (ignore-errors ,form) + (signal 'flycheck-ert-skipped ',form))) + + (defun ert-test-skipped-p (result) + (and (ert-test-failed-p result) + (eq (car (ert-test-failed-condition result)) + 'flycheck-ert-skipped))))) + + +;;; Internal variables + +(defvar flycheck-ert--resource-directory nil + "The directory to get resources from in this test suite.") + + +;;; Resource management macros + +(defmacro flycheck-ert-with-temp-buffer (&rest body) + "Eval BODY within a temporary buffer. + +Like `with-temp-buffer', but resets the modification state of the +temporary buffer to make sure that it is properly killed even if +it has a backing file and is modified." + (declare (indent 0) (debug t)) + `(with-temp-buffer + (unwind-protect + ,(macroexp-progn body) + ;; Reset modification state of the buffer, and unlink it from its backing + ;; file, if any, because Emacs refuses to kill modified buffers with + ;; backing files, even if they are temporary. + (set-buffer-modified-p nil) + (set-visited-file-name nil 'no-query)))) + +(defmacro flycheck-ert-with-file-buffer (file-name &rest body) + "Create a buffer from FILE-NAME and eval BODY. + +BODY is evaluated with `current-buffer' being a buffer with the +contents FILE-NAME." + (declare (indent 1) (debug t)) + `(let ((file-name ,file-name)) + (unless (file-exists-p file-name) + (error "%s does not exist" file-name)) + (flycheck-ert-with-temp-buffer + (insert-file-contents file-name 'visit) + (set-visited-file-name file-name 'no-query) + (cd (file-name-directory file-name)) + ;; Mark the buffer as not modified, because we just loaded the file up to + ;; now. + (set-buffer-modified-p nil) + ,@body))) + +(defmacro flycheck-ert-with-help-buffer (&rest body) + "Execute BODY and kill the help buffer afterwards. + +Use this macro to test functions that create a Help buffer." + (declare (indent 0)) + `(unwind-protect + ,(macroexp-progn body) + (when (buffer-live-p (get-buffer (help-buffer))) + (kill-buffer (help-buffer))))) + +(defmacro flycheck-ert-with-global-mode (&rest body) + "Execute BODY with Global Flycheck Mode enabled. + +After BODY, restore the old state of Global Flycheck Mode." + (declare (indent 0)) + `(let ((old-state global-flycheck-mode)) + (unwind-protect + (progn + (global-flycheck-mode 1) + ,@body) + (global-flycheck-mode (if old-state 1 -1))))) + +(defmacro flycheck-ert-with-env (env &rest body) + "Add ENV to `process-environment' in BODY. + +Execute BODY with a `process-environment' which contains all +variables from ENV added. + +ENV is an alist, where each cons cell `(VAR . VALUE)' is a +environment variable VAR to be added to `process-environment' +with VALUE." + (declare (indent 1)) + `(let ((process-environment (copy-sequence process-environment))) + (pcase-dolist (`(,var . ,value) ,env) + (setenv var value)) + ,@body)) + + +;;; Test resources +(defun flycheck-ert-resource-filename (resource-file) + "Determine the absolute file name of a RESOURCE-FILE. + +Relative file names are expanded against +`flycheck-ert--resource-directory'." + (expand-file-name resource-file flycheck-ert--resource-directory)) + +(defmacro flycheck-ert-with-resource-buffer (resource-file &rest body) + "Create a temp buffer from a RESOURCE-FILE and execute BODY. + +The absolute file name of RESOURCE-FILE is determined with +`flycheck-ert-resource-filename'." + (declare (indent 1)) + `(flycheck-ert-with-file-buffer + (flycheck-ert-resource-filename ,resource-file) + ,@body)) + + +;;; Test suite initialization + +(defun flycheck-ert-initialize (resource-dir) + "Initialize a test suite with RESOURCE-DIR. + +RESOURCE-DIR is the directory, `flycheck-ert-resource-filename' +should use to lookup resource files." + (when flycheck-ert--resource-directory + (error "Test suite already initialized")) + (let ((tests (ert-select-tests t t))) + ;; Select all tests + (unless tests + (error "No tests defined. \ +Call `flycheck-ert-initialize' after defining all tests!")) + + (setq flycheck-ert--resource-directory resource-dir) + + ;; Emacs 24.3 don't support skipped tests, so we add poor man's test + ;; skipping: We mark skipped tests as expected failures by adjusting the + ;; expected result of all test cases. Not particularly pretty, but works :) + (unless flycheck-ert-ert-can-skip + (dolist (test tests) + (let ((result (ert-test-expected-result-type test))) + (setf (ert-test-expected-result-type test) + `(or ,result (satisfies ert-test-skipped-p)))))))) + + +;;; Test case definitions +(defmacro flycheck-ert-def-checker-test (checker language name + &rest keys-and-body) + "Define a test case for a syntax CHECKER for LANGUAGE. + +CHECKER is a symbol or a list of symbols denoting syntax checkers +being tested by the test. The test case is skipped, if any of +these checkers cannot be used. LANGUAGE is a symbol or a list of +symbols denoting the programming languages supported by the +syntax checkers. This is currently only used for tagging the +test appropriately. + +NAME is a symbol denoting the local name of the test. The test +itself is ultimately named +`flycheck-define-checker/CHECKER/NAME'. If CHECKER is a list, +the first checker in the list is used for naming the test. + +Optionally, the keyword arguments `:tags' and `:expected-result' +may be given. They have the same meaning as in `ert-deftest.', +and are added to the tags and result expectations set up by this +macro. + +The remaining forms KEYS-AND-BODY denote the body of the test +case, including assertions and setup code." + (declare (indent 3)) + (unless checker + (error "No syntax checkers specified")) + (unless language + (error "No languages specified")) + (let* ((checkers (if (symbolp checker) (list checker) checker)) + (checker (car checkers)) + (languages (if (symbolp language) (list language) language)) + (language-tags (mapcar (lambda (l) (intern (format "language-%s" l))) + languages)) + (checker-tags (mapcar (lambda (c) (intern (format "checker-%s" c))) + checkers)) + (local-name (or name 'default)) + (full-name (intern (format "flycheck-define-checker/%s/%s" + checker local-name))) + (keys-and-body (ert--parse-keys-and-body keys-and-body)) + (body (cadr keys-and-body)) + (keys (car keys-and-body)) + (default-tags '(syntax-checker external-tool))) + `(ert-deftest ,full-name () + :expected-result ,(or (plist-get keys :expected-result) :passed) + :tags (append ',(append default-tags language-tags checker-tags) + ,(plist-get keys :tags)) + ,@(mapcar (lambda (c) + `(skip-unless + ;; Ignore non-command checkers + (or (not (flycheck-checker-get ',c 'command)) + (executable-find (flycheck-checker-executable ',c))))) + checkers) + ,@body))) + + +;;; Test case results + +(defun flycheck-ert-syntax-check-timed-out-p (result) + "Whether RESULT denotes a timed-out test. + +RESULT is an ERT test result object." + (and (ert-test-failed-p result) + (eq (car (ert-test-failed-condition result)) + 'flycheck-ert-syntax-check-timed-out))) + + +;;; Syntax checking in tests + +(defvar-local flycheck-ert-syntax-checker-finished nil + "Non-nil if the current checker has finished.") + +(add-hook 'flycheck-after-syntax-check-hook + (lambda () (setq flycheck-ert-syntax-checker-finished t))) + +(defconst flycheck-ert-checker-wait-time 10 + "Time to wait until a checker is finished in seconds. + +After this time has elapsed, the checker is considered to have +failed, and the test aborted with failure.") + +(define-error 'flycheck-ert-syntax-check-timed-out "Syntax check timed out.") + +(defun flycheck-ert-wait-for-syntax-checker () + "Wait until the syntax check in the current buffer is finished." + (let ((starttime (float-time))) + (while (and (not flycheck-ert-syntax-checker-finished) + (< (- (float-time) starttime) flycheck-ert-checker-wait-time)) + (accept-process-output nil 0.02)) + (unless (< (- (float-time) starttime) flycheck-ert-checker-wait-time) + (flycheck-stop) + (signal 'flycheck-ert-syntax-check-timed-out nil))) + (setq flycheck-ert-syntax-checker-finished nil)) + +(defun flycheck-ert-buffer-sync () + "Like `flycheck-buffer', but synchronously." + (setq flycheck-ert-syntax-checker-finished nil) + (should (not (flycheck-running-p))) + (flycheck-mode) ;; This will only start a deferred check, + (should (flycheck-get-checker-for-buffer)) + (flycheck-buffer) ;; …so we need an explicit manual check + ;; After starting the check, the checker should either be running now, or + ;; already be finished (if it was fast). + (should (or flycheck-current-syntax-check + flycheck-ert-syntax-checker-finished)) + ;; Also there should be no deferred check pending anymore + (should-not (flycheck-deferred-check-p)) + (flycheck-ert-wait-for-syntax-checker)) + +(defun flycheck-ert-ensure-clear () + "Clear the current buffer. + +Raise an assertion error if the buffer is not clear afterwards." + (flycheck-clear) + (should (not flycheck-current-errors)) + (should (not (-any? (lambda (ov) (overlay-get ov 'flycheck-overlay)) + (overlays-in (point-min) (point-max)))))) + + +;;; Test assertions + +(defun flycheck-error-without-group (err) + "Return a copy ERR with the `group' property set to nil." + (let ((copy (copy-flycheck-error err))) + (setf (flycheck-error-group copy) nil) + copy)) + +(defun flycheck-ert-should-overlay (error) + "Test that ERROR has a proper overlay in the current buffer. + +ERROR is a Flycheck error object." + (let* ((overlay (-first (lambda (ov) + (equal (flycheck-error-without-group + (overlay-get ov 'flycheck-error)) + (flycheck-error-without-group error))) + (flycheck-overlays-in 0 (+ 1 (buffer-size))))) + (region + ;; Overlays of errors from other files are on the first line + (if (flycheck-relevant-error-other-file-p error) + (cons (point-min) + (save-excursion (goto-char (point-min)) (point-at-eol))) + (flycheck-error-region-for-mode error 'symbols))) + (level (flycheck-error-level error)) + (category (flycheck-error-level-overlay-category level)) + (face (get category 'face)) + (fringe-bitmap (flycheck-error-level-fringe-bitmap level)) + (fringe-face (flycheck-error-level-fringe-face level)) + (fringe-icon (list 'left-fringe fringe-bitmap fringe-face))) + (should overlay) + (should (overlay-get overlay 'flycheck-overlay)) + (should (= (overlay-start overlay) (car region))) + (should (= (overlay-end overlay) (cdr region))) + (should (eq (overlay-get overlay 'face) face)) + (should (equal (get-char-property 0 'display + (overlay-get overlay 'before-string)) + fringe-icon)) + (should (eq (overlay-get overlay 'category) category)) + (should (equal (flycheck-error-without-group (overlay-get overlay + 'flycheck-error)) + (flycheck-error-without-group error))))) + +(defun flycheck-ert-sort-errors (errors) + "Sort ERRORS by `flycheck-error-<'." + (seq-sort #'flycheck-error-< errors)) + +(defun flycheck-ert-should-errors (&rest errors) + "Test that the current buffers has ERRORS. + +ERRORS is a list of errors expected to be present in the current +buffer. Each error is given as a list of arguments to +`flycheck-error-new-at'. + +If ERRORS are omitted, test that there are no errors at all in +the current buffer. + +With ERRORS, test that each error in ERRORS is present in the +current buffer, and that the number of errors in the current +buffer is equal to the number of given ERRORS. In other words, +check that the buffer has all ERRORS, and no other errors." + (let ((expected (flycheck-ert-sort-errors + (mapcar (apply-partially #'apply #'flycheck-error-new-at) + errors))) + (current (flycheck-ert-sort-errors flycheck-current-errors))) + (should (equal (mapcar #'flycheck-error-without-group expected) + (mapcar #'flycheck-error-without-group current))) + ;; Check that related errors are the same + (cl-mapcar + (lambda (err1 err2) + (should (equal (flycheck-ert-sort-errors + (mapcar #'flycheck-error-without-group + (flycheck-related-errors err1 expected))) + (flycheck-ert-sort-errors + (mapcar #'flycheck-error-without-group + (flycheck-related-errors err2)))))) + expected current) + (mapc #'flycheck-ert-should-overlay expected)) + (should (= (length errors) + (length (flycheck-overlays-in (point-min) (point-max)))))) + +(define-error 'flycheck-ert-suspicious-checker "Suspicious state from checker") + +(defun flycheck-ert-should-syntax-check-in-buffer (&rest errors) + "Test a syntax check in BUFFER, expecting ERRORS. + +This is like `flycheck-ert-should-syntax-check', but with a +buffer in the right mode instead of a file." + ;; Load safe file-local variables because some tests depend on them + (let ((enable-local-variables :safe) + ;; Disable all hooks at this place, to prevent 3rd party packages + ;; from interfering + (hack-local-variables-hook)) + (hack-local-variables)) + ;; Configure config file locating for unit tests + (let ((process-hook-called 0) + (suspicious nil)) + (add-hook 'flycheck-process-error-functions + (lambda (_err) + (setq process-hook-called (1+ process-hook-called)) + nil) + nil :local) + (add-hook 'flycheck-status-changed-functions + (lambda (status) + (when (eq status 'suspicious) + (setq suspicious t))) + nil :local) + (flycheck-ert-buffer-sync) + (when suspicious + (signal 'flycheck-ert-suspicious-checker nil)) + (apply #'flycheck-ert-should-errors errors) + (should (= process-hook-called (length errors)))) + (flycheck-ert-ensure-clear)) + +(defun flycheck-ert-should-syntax-check (resource-file modes &rest errors) + "Test a syntax check in RESOURCE-FILE with MODES. + +RESOURCE-FILE is the file to check. MODES is a single major mode +symbol or a list thereof, specifying the major modes to syntax +check with. If more than one major mode is specified, the test +is run for each mode separately, so if you give three major +modes, the entire test will run three times. ERRORS is the list +of expected errors, as in `flycheck-ert-should-errors'. If +omitted, the syntax check must not emit any errors. The errors +are cleared after each test. + +The syntax checker is selected via standard syntax checker +selection. To test a specific checker, you need to set +`flycheck-checker' or `flycheck-disabled-checkers' accordingly +before using this predicate, depending on whether you want to use +manual or automatic checker selection. + +During the syntax check, configuration files of syntax checkers +are also searched in the `config-files' sub-directory of the +resource directory." + (when (symbolp modes) + (setq modes (list modes))) + (dolist (mode modes) + (unless (fboundp mode) + (ert-skip (format "%S missing" mode))) + (flycheck-ert-with-resource-buffer resource-file + (funcall mode) + (apply #'flycheck-ert-should-syntax-check-in-buffer errors)))) + +(defun flycheck-ert-at-nth-error (n) + "Determine whether point is at the N'th Flycheck error. + +Return non-nil if the point is at the N'th Flycheck error in the +current buffer. Otherwise return nil." + (let* ((error (nth (1- n) flycheck-current-errors)) + (mode flycheck-highlighting-mode) + (region (flycheck-error-region-for-mode error mode))) + (and (member error (flycheck-overlay-errors-at (point))) + (= (point) (car region))))) + +(defun flycheck-ert-explain--at-nth-error (n) + "Explain a failed at-nth-error predicate at N." + (let ((errors (flycheck-overlay-errors-at (point)))) + (if (null errors) + (format "Expected to be at error %s, but no error at point %s" + n (point)) + (let ((pos (cl-position (car errors) flycheck-current-errors))) + (format "Expected to be at point %s and error %s, \ +but point %s is at error %s" + (car (flycheck-error-region-for-mode + (nth (1- n) flycheck-current-errors) + flycheck-highlighting-mode)) + n (point) (1+ pos)))))) + +(put 'flycheck-ert-at-nth-error 'ert-explainer + 'flycheck-ert-explain--at-nth-error) + +(provide 'flycheck-ert) + +;;; flycheck-ert.el ends here diff --git a/flycheck.el b/flycheck.el new file mode 100644 index 0000000..30a4a38 --- /dev/null +++ b/flycheck.el @@ -0,0 +1,12402 @@ +;;; flycheck.el --- On-the-fly syntax checking -*- lexical-binding: t; -*- + +;; Copyright (C) 2017-2020 Flycheck contributors +;; Copyright (C) 2012-2016 Sebastian Wiesner and Flycheck contributors +;; Copyright (C) 2013, 2014 Free Software Foundation, Inc. +;; +;; Author: Sebastian Wiesner +;; Maintainer: Clément Pit-Claudel +;; fmdkdd +;; URL: http://www.flycheck.org +;; Keywords: convenience, languages, tools +;; Version: 32-cvs +;; Package-Requires: ((dash "2.12.1") (pkg-info "0.4") (let-alist "1.0.4") (seq "1.11") (emacs "24.3")) + +;; This file is not part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; On-the-fly syntax checking for GNU Emacs 24. +;; +;; Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs, +;; intended as replacement for the older Flymake extension which is part of GNU +;; Emacs. +;; +;; Flycheck automatically checks buffers for errors while you type, and reports +;; warnings and errors directly in the buffer and in an optional IDE-like error +;; list. +;; +;; It comes with a rich interface for custom syntax checkers and other +;; extensions, and has already many 3rd party extensions adding new features. +;; +;; Please read the online manual at http://www.flycheck.org for more +;; information. You can open the manual directly from Emacs with `M-x +;; flycheck-manual'. +;; +;; # Setup +;; +;; Flycheck works best on Unix systems. It does not officially support Windows, +;; but tries to maintain Windows compatibility and should generally work fine on +;; Windows, too. +;; +;; To enable Flycheck add the following to your init file: +;; +;; (add-hook 'after-init-hook #'global-flycheck-mode) +;; +;; Flycheck will then automatically check buffers in supported languages, as +;; long as all necessary tools are present. Use `flycheck-verify-setup' to +;; troubleshoot your Flycheck setup. + +;;; Code: + +(eval-when-compile + (require 'let-alist) ; `let-alist' + (require 'compile) ; Compile Mode integration + (require 'jka-compr) ; To inhibit compression of temp files + (require 'pcase) ; `pcase-dolist' (`pcase' itself is autoloaded) + ) + +(require 'dash) + +(require 'seq) ; Sequence functions +(require 'subr-x nil 'no-error) ; Additional utilities, Emacs 24.4 and upwards +(require 'cl-lib) ; `cl-defstruct' and CL utilities +(require 'tabulated-list) ; To list errors +(require 'easymenu) ; Flycheck Mode menu definition +(require 'rx) ; Regexp fanciness in `flycheck-define-checker' +(require 'help-mode) ; `define-button-type' +(require 'find-func) ; `find-function-regexp-alist' +(require 'json) ; `flycheck-parse-tslint' +(require 'ansi-color) ; `flycheck-parse-with-patterns-without-color' + + +;; Declare a bunch of dynamic variables that we need from other modes +(defvar sh-shell) ; For shell script checker predicates +(defvar ess-language) ; For r-lintr predicate +(defvar markdown-hide-markup) ; +(defvar markdown-fontify-code-block-default-mode) ; For rust-error-explainer +(defvar markdown-fontify-code-blocks-natively) ; + +;; Tell the byte compiler about autoloaded functions from packages +(declare-function pkg-info-version-info "pkg-info" (package)) + + +;;; Compatibility +(eval-and-compile + (unless (fboundp 'string-suffix-p) + ;; TODO: Remove when dropping support for Emacs 24.3 and earlier + (defun string-suffix-p (suffix string &optional ignore-case) + "Return non-nil if SUFFIX is a suffix of STRING. +If IGNORE-CASE is non-nil, the comparison is done without paying +attention to case differences." + (let ((start-pos (- (length string) (length suffix)))) + (and (>= start-pos 0) + (eq t (compare-strings suffix nil nil + string start-pos nil ignore-case)))))) + + (defalias 'flycheck--format-message + (if (fboundp 'format-message) #'format-message #'format)) + + ;; TODO: Remove when dropping support for Emacs 24.3 and earlier + (unless (featurep 'subr-x) + ;; `subr-x' function for Emacs 24.3 and below + (defsubst string-join (strings &optional separator) + "Join all STRINGS using SEPARATOR." + (mapconcat 'identity strings separator)) + + (defsubst string-trim-left (string) + "Remove leading whitespace from STRING." + (if (string-match "\\`[ \t\n\r]+" string) + (replace-match "" t t string) + string)) + + (defsubst string-trim-right (string) + "Remove trailing whitespace from STRING." + (if (string-match "[ \t\n\r]+\\'" string) + (replace-match "" t t string) + string)) + + (defsubst string-trim (string) + "Remove leading and trailing whitespace from STRING." + (string-trim-left (string-trim-right string))) + + (defsubst string-empty-p (string) + "Check whether STRING is empty." + (string= string "")))) + + +;;; Customization +(defgroup flycheck nil + "Modern on-the-fly syntax checking for GNU Emacs." + :prefix "flycheck-" + :group 'tools + :link '(url-link :tag "Website" "http://www.flycheck.org") + :link '(url-link :tag "Github" "https://github.com/flycheck/flycheck")) + +(defgroup flycheck-config-files nil + "Configuration files for on-the-fly syntax checkers." + :prefix "flycheck-" + :group 'flycheck) + +(defgroup flycheck-options nil + "Options for on-the-fly syntax checkers." + :prefix "flycheck-" + :group 'flycheck) + +(defgroup flycheck-executables nil + "Executables of syntax checkers." + :prefix "flycheck-" + :group 'flycheck) + +(defgroup flycheck-faces nil + "Faces used by on-the-fly syntax checking." + :prefix "flycheck-" + :group 'flycheck) + +(defcustom flycheck-checkers + '(ada-gnat + asciidoctor + asciidoc + awk-gawk + bazel-buildifier + c/c++-clang + c/c++-gcc + c/c++-cppcheck + cfengine + chef-foodcritic + coffee + coffee-coffeelint + coq + css-csslint + css-stylelint + cuda-nvcc + cwl + d-dmd + dockerfile-hadolint + elixir-credo + emacs-lisp + emacs-lisp-checkdoc + ember-template + erlang-rebar3 + erlang + eruby-erubis + eruby-ruumba + fortran-gfortran + go-gofmt + go-golint + go-vet + go-build + go-test + go-errcheck + go-unconvert + go-staticcheck + groovy + haml + handlebars + haskell-stack-ghc + haskell-ghc + haskell-hlint + html-tidy + javascript-eslint + javascript-jshint + javascript-standard + json-jsonlint + json-python-json + json-jq + jsonnet + less + less-stylelint + llvm-llc + lua-luacheck + lua + markdown-markdownlint-cli + markdown-mdl + nix + nix-linter + opam + perl + perl-perlcritic + php + php-phpmd + php-phpcs + processing + proselint + protobuf-protoc + protobuf-prototool + pug + puppet-parser + puppet-lint + python-flake8 + python-pylint + python-pycompile + python-pyright + python-mypy + r-lintr + racket + rpm-rpmlint + rst-sphinx + rst + ruby-rubocop + ruby-standard + ruby-reek + ruby-rubylint + ruby + ruby-jruby + rust-cargo + rust + rust-clippy + scala + scala-scalastyle + scheme-chicken + scss-lint + scss-stylelint + sass/scss-sass-lint + sass + scss + sh-bash + sh-posix-dash + sh-posix-bash + sh-zsh + sh-shellcheck + slim + slim-lint + sql-sqlint + systemd-analyze + tcl-nagelfar + terraform + terraform-tflint + tex-chktex + tex-lacheck + texinfo + textlint + typescript-tslint + verilog-verilator + vhdl-ghdl + xml-xmlstarlet + xml-xmllint + yaml-jsyaml + yaml-ruby + yaml-yamllint) + "Syntax checkers available for automatic selection. + +A list of Flycheck syntax checkers to choose from when syntax +checking a buffer. Flycheck will automatically select a suitable +syntax checker from this list, unless `flycheck-checker' is set, +either directly or with `flycheck-select-checker'. + +You should not need to change this variable normally. In order +to disable syntax checkers, please use +`flycheck-disabled-checkers'. This variable is intended for 3rd +party extensions to tell Flycheck about new syntax checkers. + +Syntax checkers in this list must be defined with +`flycheck-define-checker'." + :group 'flycheck + :type '(repeat (symbol :tag "Checker")) + :risky t) + +(defcustom flycheck-disabled-checkers nil + "Syntax checkers excluded from automatic selection. + +A list of Flycheck syntax checkers to exclude from automatic +selection. Flycheck will never automatically select a syntax +checker in this list, regardless of the value of +`flycheck-checkers'. + +However, syntax checkers in this list are still available for +manual selection with `flycheck-select-checker'. + +Use this variable to disable syntax checkers, instead of removing +the syntax checkers from `flycheck-checkers'. You may also use +this option as a file or directory local variable to disable +specific checkers in individual files and directories +respectively." + :group 'flycheck + :type '(repeat (symbol :tag "Checker")) + :package-version '(flycheck . "0.16") + :safe #'flycheck-symbol-list-p) +(make-variable-buffer-local 'flycheck-disabled-checkers) + +(defvar-local flycheck--automatically-disabled-checkers nil + "List of syntax checkers automatically disabled for this buffer. + +A checker can be automatically disabled in two cases: + +1. Its `:enabled' predicate returned false. +2. It returned too many errors (see `flycheck-checker-error-threshold'). + +To trigger a reverification from Emacs Lisp code, do not modify +this variable: use `flycheck-reset-enabled-checker'.") + +(defvar-local flycheck-checker nil + "Syntax checker to use for the current buffer. + +If unset or nil, automatically select a suitable syntax checker +from `flycheck-checkers' on every syntax check. + +If set to a syntax checker only use this syntax checker and never +select one from `flycheck-checkers' automatically. The syntax +checker is used regardless of whether it is contained in +`flycheck-checkers' or `flycheck-disabled-checkers'. If the +syntax checker is unusable in the current buffer an error is +signaled. + +A syntax checker assigned to this variable must be defined with +`flycheck-define-checker'. + +Use the command `flycheck-select-checker' to select a syntax +checker for the current buffer, or set this variable as file +local variable to always use a specific syntax checker for a +file. See Info Node `(emacs)Specifying File Variables' for more +information about file variables.") +(put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p) + +(defcustom flycheck-locate-config-file-functions nil + "Functions to locate syntax checker configuration files. + +Each function in this hook must accept two arguments: The value +of the configuration file variable, and the syntax checker +symbol. It must return either a string with an absolute path to +the configuration file, or nil, if it cannot locate the +configuration file. + +The functions in this hook are called in order of appearance, until a +function returns non-nil. The configuration file returned by that +function is then given to the syntax checker if it exists. + +This variable is an abnormal hook. See Info +node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t) + +(defcustom flycheck-checker-error-threshold 400 + "Maximum errors allowed per syntax checker. + +The value of this variable is either an integer denoting the +maximum number of errors per syntax checker and buffer, or nil to +not limit the errors reported from a syntax checker. + +If this variable is a number and a syntax checker reports more +errors than the value of this variable, its errors are not +discarded, and not highlighted in the buffer or available in the +error list. The affected syntax checker is also disabled for +future syntax checks of the buffer." + :group 'flycheck + :type '(choice (const :tag "Do not limit reported errors" nil) + (integer :tag "Maximum number of errors")) + :risky t + :package-version '(flycheck . "0.22")) + +(defcustom flycheck-process-error-functions nil + "Functions to process errors. + +Each function in this hook must accept a single argument: A +Flycheck error to process. + +All functions in this hook are called in order of appearance, +until a function returns non-nil. Thus, a function in this hook +may return nil, to allow for further processing of the error, or +any non-nil value, to indicate that the error was fully processed +and inhibit any further processing. + +The functions are called for each newly parsed error immediately +after the corresponding syntax checker finished. At this stage, +the overlays from the previous syntax checks are still present, +and there may be further syntax checkers in the chain. + +This variable is an abnormal hook. See Info +node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :package-version '(flycheck . "0.13") + :risky t) + +(defcustom flycheck-display-errors-delay 0.9 + "Delay in seconds before displaying errors at point. + +Use floating point numbers to express fractions of seconds." + :group 'flycheck + :type 'number + :package-version '(flycheck . "0.15") + :safe #'numberp) + +(defcustom flycheck-display-errors-function #'flycheck-display-error-messages + "Function to display error messages. + +If set to a function, call the function with the list of errors +to display as single argument. Each error is an instance of the +`flycheck-error' struct. + +If set to nil, do not display errors at all." + :group 'flycheck + :type '(choice (const :tag "Display error messages" + flycheck-display-error-messages) + (const :tag "Display error messages only if no error list" + flycheck-display-error-messages-unless-error-list) + (function :tag "Error display function")) + :package-version '(flycheck . "0.13") + :risky t) + +(defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages + "Function to compute the contents of the error tooltips. + +If set to a function, call the function with the list of errors +to display as single argument. Each error is an instance of the +`flycheck-error' struct. The function is used to set the +help-echo property of flycheck error overlays. It should return +a string, which is displayed when the user hovers over an error +or presses \\[display-local-help]. + +If set to nil, do not show error tooltips." + :group 'flycheck + :type '(choice (const :tag "Concatenate error messages to form a tooltip" + flycheck-help-echo-all-error-messages) + (function :tag "Help echo function")) + :package-version '(flycheck . "0.25") + :risky t) + +(defcustom flycheck-command-wrapper-function #'identity + "Function to modify checker commands before execution. + +The value of this option is a function which is given a list +containing the full command of a syntax checker after +substitution through `flycheck-substitute-argument' but before +execution. The function may return a new command for Flycheck to +execute. + +The default value is `identity' which does not change the +command. You may provide your own function to run Flycheck +commands through `bundle exec', `nix-shell' or similar wrappers." + :group 'flycheck + :type '(choice (const :tag "Do not modify commands" identity) + (function :tag "Modify command with a custom function")) + :package-version '(flycheck . "0.25") + :risky t) + +(defcustom flycheck-executable-find #'flycheck-default-executable-find + "Function to search for executables. + +The value of this option is a function which is given the name or +path of an executable and shall return the full path to the +executable, or nil if the executable does not exit. + +The default is `flycheck-default-executable-find', which searches +variable `exec-path' when given a command name, and resolves +paths to absolute ones. You can customize this option to search +for checkers in other environments such as bundle or NixOS +sandboxes." + :group 'flycheck + :type '(choice + (const :tag "Search executables in `exec-path'" + flycheck-default-executable-find) + (function :tag "Search executables with a custom function")) + :package-version '(flycheck . "32") + :risky t) + +(defun flycheck-default-executable-find (executable) + "Resolve EXECUTABLE to a full path. + +Like `executable-find', but supports relative paths. + +Attempts invoking `executable-find' first; if that returns nil, +and EXECUTABLE contains a directory component, expands to a full +path and tries invoking `executable-find' again." + ;; file-name-directory returns non-nil iff the given path has a + ;; directory component. + (or + (executable-find executable) + (when (file-name-directory executable) + (executable-find (expand-file-name executable))))) + +(defcustom flycheck-indication-mode 'left-fringe + "The indication mode for Flycheck errors. + +This variable controls how Flycheck indicates errors in buffers. +May be `left-fringe', `right-fringe', `left-margin', +`right-margin', or nil. + +If set to `left-fringe' or `right-fringe', indicate errors via +icons in the left and right fringe respectively. If set to +`left-margin' or `right-margin', use the margins instead. + +If set to nil, do not indicate errors and warnings, but just +highlight them according to `flycheck-highlighting-mode'." + :group 'flycheck + :type '(choice (const :tag "Indicate in the left fringe" left-fringe) + (const :tag "Indicate in the right fringe" right-fringe) + (const :tag "Indicate in the left margin" left-margin) + (const :tag "Indicate in the right margin" right-margin) + (const :tag "Do not indicate" nil)) + :safe #'symbolp) + +(defcustom flycheck-highlighting-mode 'symbols + "The highlighting mode for Flycheck errors and warnings. + +The highlighting mode controls how Flycheck highlights errors in +buffers when a checker only reports the starting position of an +error. The following modes are known: + +`columns' + Highlight a single character. If the error does not have a column, + highlight the whole line. + +`symbols' + Highlight a full symbol if there is any, otherwise behave like `columns'. + This is the default. + +`sexps' + Highlight a full expression, if there is any, otherwise behave like + `columns'. Note that this mode can be *very* slow in some major modes. + +`lines' + Highlight the whole line. + +nil + Do not highlight errors at all. However, errors will still + be reported in the mode line and in error message popups, + and indicated according to `flycheck-indication-mode'." + :group 'flycheck + :type '(choice (const :tag "Highlight columns only" columns) + (const :tag "Highlight symbols" symbols) + (const :tag "Highlight expressions" sexps) + (const :tag "Highlight whole lines" lines) + (const :tag "Do not highlight errors" nil)) + :package-version '(flycheck . "0.14") + :safe #'symbolp) + +(defvar flycheck-current-errors) +(defun flycheck-refresh-fringes-and-margins () + "Refresh fringes and margins of all windows displaying the current buffer. + +If any errors are currently shown, launch a new check, to adjust +to a potential new indication mode." + (dolist (win (get-buffer-window-list)) + (set-window-margins win left-margin-width right-margin-width) + (set-window-fringes win left-fringe-width right-fringe-width)) + (when flycheck-current-errors + (flycheck-buffer))) + +(defun flycheck-set-indication-mode (&optional mode) + "Set `flycheck-indication-mode' to MODE and adjust margins and fringes. + +When MODE is nil, adjust window parameters without changing the +mode. This function can be useful as a `flycheck-mode-hook', +especially if you use margins only in Flycheck buffers. + +When MODE is `left-margin', the left fringe is reduced to 1 pixel +to save space." + (interactive (list (intern (completing-read + "Mode: " '("left-fringe" "right-fringe" + "left-margin" "right-margin") + nil t nil nil + (prin1-to-string flycheck-indication-mode))))) + (setq mode (or mode flycheck-indication-mode)) + (pcase mode + ((or `left-fringe `right-fringe) + (setq left-fringe-width 8 right-fringe-width 8 + left-margin-width 0 right-margin-width 0)) + (`left-margin + (setq left-fringe-width 1 right-fringe-width 8 + left-margin-width 1 right-margin-width 0)) + (`right-margin + (setq left-fringe-width 8 right-fringe-width 8 + left-margin-width 0 right-margin-width 1)) + (_ (user-error "Invalid indication mode"))) + (setq-local flycheck-indication-mode mode) + (flycheck-refresh-fringes-and-margins)) + +(define-widget 'flycheck-highlighting-style 'lazy + "A value for `flycheck-highlighting-style'." + :offset 2 + :format "%t: Use %v" + :type '(choice + :format "%[Value Menu%] %v" + (const :tag "no highlighting" nil) + (const :tag "a face indicating the error level" level-face) + (list :tag "a pair of delimiters" + (const :format "" delimiters) + (string :tag "Before") + (string :tag "After")) + (list :tag "a conditional mix of styles" + (const :format "" conditional) + (integer :tag "Up to this many lines") + (flycheck-highlighting-style :format "Use %v") + (flycheck-highlighting-style :format "Otherwise, use %v")))) + +(defun flycheck--make-highlighting-delimiter (char) + "Make a highlighting bracket symbol by repeating CHAR twice." + (compose-chars ?\s + ;; '(Bl . Br) ?\s + '(Bc Br 30 0) char + '(Bc Bl -30 0) char)) + +(defcustom flycheck-highlighting-style + `(conditional 4 level-face (delimiters "" "")) + "The highlighting style for Flycheck errors and warnings. + +The highlighting style controls how Flycheck highlights error +regions in buffers. The following styles are supported: + +nil + Do not highlight errors. Same as setting + `flycheck-highlighting-mode' to nil. + +`level-face' + Chose a face depending on the severity of the error, and + apply it to the whole error text. See also the + `flycheck-define-error-level' and `flycheck-error', + `flycheck-warning', and `flycheck-info' faces. + +\(`delimiters' BEFORE AFTER) + Draw delimiters on each side of the error. BEFORE and AFTER + indicate which delimiters to use. If they are strings, they + are used as-is. If they are characters, they are repeated + twice and composed into a single character. Delimiters use + the fringe face corresponding to the severity of each error, + as well as the `flycheck-error-delimiter' face. Delimited + text has the `flycheck-delimited-error' face. + +\(`conditional' NLINES S1 S2) + Use style S1 for errors spanning up to NLINES lines, and + style S2 otherwise. + +See also `flycheck-highlighting-mode' and +`flycheck-indication-mode'." + :group 'flycheck + :type 'flycheck-highlighting-style + :package-version '(flycheck . "32") + :safe t) + +(defcustom flycheck-check-syntax-automatically '(save + idle-change + new-line + mode-enabled) + "When Flycheck should check syntax automatically. + +This variable is a list of events that may trigger syntax checks. +The following events are known: + +`save' + Check syntax immediately after the buffer was saved. + +`idle-change' + Check syntax a short time (see `flycheck-idle-change-delay') + after the last change to the buffer. + +`idle-buffer-switch' + Check syntax a short time (see `flycheck-idle-buffer-switch-delay') + after the user switches to a buffer. + +`new-line' + Check syntax immediately after a new line was inserted into + the buffer. + +`mode-enabled' + Check syntax immediately when variable `flycheck-mode' is + non-nil. + +Flycheck performs a syntax checks only on events, which are +contained in this list. For instance, if the value of this +variable is `(mode-enabled save)', Flycheck will only check if +the mode is enabled or the buffer was saved, but never after +changes to the buffer contents. + +If nil, never check syntax automatically. In this case, use +`flycheck-buffer' to start a syntax check manually." + :group 'flycheck + :type '(set (const :tag "After the buffer was saved" save) + (const :tag "After the buffer was changed and idle" idle-change) + (const + :tag "After switching the current buffer" idle-buffer-switch) + (const :tag "After a new line was inserted" new-line) + (const :tag "After `flycheck-mode' was enabled" mode-enabled)) + :package-version '(flycheck . "0.12") + :safe #'flycheck-symbol-list-p) + +(defcustom flycheck-idle-change-delay 0.5 + "How many seconds to wait after a change before checking syntax. + +After the buffer was changed, Flycheck will wait as many seconds +as the value of this variable before starting a syntax check. If +the buffer is modified during this time, Flycheck will wait +again. + +This variable has no effect, if `idle-change' is not contained in +`flycheck-check-syntax-automatically'." + :group 'flycheck + :type 'number + :package-version '(flycheck . "0.13") + :safe #'numberp) + +(defcustom flycheck-idle-buffer-switch-delay 0.5 + "How many seconds to wait after switching buffers before checking syntax. + +After the user switches to a new buffer, Flycheck will wait as +many seconds as the value of this variable before starting a +syntax check. If the user switches to another buffer during this +time, whether a syntax check is still performed depends on the +value of `flycheck-buffer-switch-check-intermediate-buffers'. + +This variable has no effect if `idle-buffer-switch' is not +contained in `flycheck-check-syntax-automatically'." + :group 'flycheck + :type 'number + :package-version '(flycheck . "32") + :safe #'numberp) + +(defcustom flycheck-buffer-switch-check-intermediate-buffers nil + "Whether to check syntax in a buffer you only visit briefly. + +If nil, then when you switch to a buffer but switch to another +buffer before the syntax check is performed, then the check is +canceled. If non-nil, then syntax checks due to switching +buffers are always performed. This only affects buffer switches +that happen less than `flycheck-idle-buffer-switch-delay' seconds +apart. + +This variable has no effect if `idle-buffer-switch' is not +contained in `flycheck-check-syntax-automatically'." + :group 'flycheck + :type 'boolean + :package-version '(flycheck . "32") + :safe #'booleanp) + +(defcustom flycheck-standard-error-navigation t + "Whether to support error navigation with `next-error'. + +If non-nil, enable navigation of Flycheck errors with +`next-error', `previous-error' and `first-error'. Otherwise, +these functions just navigate errors from compilation modes. + +Flycheck error navigation with `flycheck-next-error', +`flycheck-previous-error' and `flycheck-first-error' is always +enabled, regardless of the value of this variable. + +Note that this setting only takes effect when variable +`flycheck-mode' is non-nil. Changing it will not affect buffers +where variable `flycheck-mode' is already non-nil." + :group 'flycheck + :type 'boolean + :package-version '(flycheck . "0.15") + :safe #'booleanp) + +(define-widget 'flycheck-minimum-level 'lazy + "A radio-type choice of minimum error levels. + +See `flycheck-navigation-minimum-level' and +`flycheck-error-list-minimum-level'." + :type '(radio (const :tag "All locations" nil) + (const :tag "Informational messages" info) + (const :tag "Warnings" warning) + (const :tag "Errors" error) + (symbol :tag "Custom error level"))) + +(defcustom flycheck-navigation-minimum-level nil + "The minimum level of errors to navigate. + +If set to an error level, only navigate errors whose error level +is at least as severe as this one. If nil, navigate all errors." + :group 'flycheck + :type 'flycheck-minimum-level + :safe #'flycheck-error-level-p + :package-version '(flycheck . "0.21")) + +(defcustom flycheck-error-list-minimum-level nil + "The minimum level of errors to display in the error list. + +If set to an error level, only display errors whose error level +is at least as severe as this one in the error list. If nil, +display all errors. + +This is the default level, used when the error list is opened. +You can temporarily change the level using +\\[flycheck-error-list-set-filter], or reset it to this value +using \\[flycheck-error-list-reset-filter]." + :group 'flycheck + :type 'flycheck-minimum-level + :safe #'flycheck-error-level-p + :package-version '(flycheck . "0.24")) + +(defcustom flycheck-relevant-error-other-file-minimum-level 'error + "The minimum level of errors from other files to display in this buffer. + +If set to an error level, only display errors from other files +whose error level is at least as severe as this one. If nil, +display all errors from other files." + :group 'flycheck + :type 'flycheck-minimum-level + :safe #'flycheck-error-level-p + :package-version '(flycheck . "32")) + +(defcustom flycheck-relevant-error-other-file-show t + "Whether to show errors from other files." + :group 'flycheck + :type 'boolean + :package-version '(flycheck . "32") + :safe #'booleanp) + +(defcustom flycheck-completing-read-function #'completing-read + "Function to read from minibuffer with completion. + +The function must be compatible to the built-in `completing-read' +function." + :group 'flycheck + :type '(choice (const :tag "Default" completing-read) + (const :tag "IDO" ido-completing-read) + (function :tag "Custom function")) + :risky t + :package-version '(flycheck . "26")) + +(defcustom flycheck-temp-prefix "flycheck" + "Prefix for temporary files created by Flycheck." + :group 'flycheck + :type 'string + :package-version '(flycheck . "0.19") + :risky t) + +(defcustom flycheck-mode-hook nil + "Hooks to run after command `flycheck-mode' is toggled." + :group 'flycheck + :type 'hook + :risky t) + +(defcustom flycheck-after-syntax-check-hook nil + "Functions to run after each syntax check. + +This hook is run after a syntax check was finished. + +At this point, *all* chained checkers were run, and all errors +were parsed, highlighted and reported. The variable +`flycheck-current-errors' contains all errors from all syntax +checkers run during the syntax check, so you can apply any error +analysis functions. + +Note that this hook does *not* run after each individual syntax +checker in the syntax checker chain, but only after the *last +checker*. + +This variable is a normal hook. See Info node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t) + +(defcustom flycheck-before-syntax-check-hook nil + "Functions to run before each syntax check. + +This hook is run right before a syntax check starts. + +Error information from the previous syntax check is *not* +cleared before this hook runs. + +Note that this hook does *not* run before each individual syntax +checker in the syntax checker chain, but only before the *first +checker*. + +This variable is a normal hook. See Info node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t) + +(defcustom flycheck-syntax-check-failed-hook nil + "Functions to run if a syntax check failed. + +This hook is run whenever an error occurs during Flycheck's +internal processing. No information about the error is given to +this hook. + +You should use this hook to conduct additional cleanup actions +when Flycheck failed. + +This variable is a normal hook. See Info node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t) + +(defcustom flycheck-status-changed-functions nil + "Functions to run if the Flycheck status changed. + +This hook is run whenever the status of Flycheck changes. Each +hook function takes the status symbol as single argument, as +given to `flycheck-report-status', which see. + +This variable is an abnormal hook. See Info +node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t + :package-version '(flycheck . "0.20")) + +(defcustom flycheck-error-list-after-refresh-hook nil + "Functions to run after the error list was refreshed. + +This hook is run whenever the error list is refreshed. + +This variable is a normal hook. See Info node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t + :package-version '(flycheck . "0.21")) + +(defface flycheck-error-delimiter + `((t)) + "Flycheck face for errors spanning multiple lines. + +See `flycheck-highlighting-style' for details on when this face +is used." + :package-version '(flycheck . "32") + :group 'flycheck-faces) + +(defface flycheck-delimited-error + `((t)) + "Flycheck face for errors spanning multiple lines. + +See `flycheck-highlighting-style' for details on when this face +is used." + :package-version '(flycheck . "32") + :group 'flycheck-faces) + +(defface flycheck-error + '((((supports :underline (:style wave))) + :underline (:style wave :color "Red1")) + (t + :underline t :inherit error)) + "Flycheck face for errors." + :package-version '(flycheck . "0.13") + :group 'flycheck-faces) + +(defface flycheck-warning + '((((supports :underline (:style wave))) + :underline (:style wave :color "DarkOrange")) + (t + :underline t :inherit warning)) + "Flycheck face for warnings." + :package-version '(flycheck . "0.13") + :group 'flycheck-faces) + +(defface flycheck-info + '((((supports :underline (:style wave))) + :underline (:style wave :color "ForestGreen")) + (t + :underline t :inherit success)) + "Flycheck face for informational messages." + :package-version '(flycheck . "0.15") + :group 'flycheck-faces) + +(defface flycheck-fringe-error + '((t :inherit error)) + "Flycheck face for fringe error indicators." + :package-version '(flycheck . "0.13") + :group 'flycheck-faces) + +(defface flycheck-fringe-warning + '((t :inherit warning)) + "Flycheck face for fringe warning indicators." + :package-version '(flycheck . "0.13") + :group 'flycheck-faces) + +(defface flycheck-fringe-info + ;; Semantically `success' is probably not the right face, but it looks nice as + ;; a base face + '((t :inherit success)) + "Flycheck face for fringe info indicators." + :package-version '(flycheck . "0.15") + :group 'flycheck-faces) + +(defface flycheck-error-list-error + '((t :inherit error)) + "Flycheck face for error messages in the error list." + :package-version '(flycheck . "0.16") + :group 'flycheck-faces) + +(defface flycheck-error-list-warning + '((t :inherit warning)) + "Flycheck face for warning messages in the error list." + :package-version '(flycheck . "0.16") + :group 'flycheck-faces) + +(defface flycheck-error-list-info + '((t :inherit success)) + "Flycheck face for info messages in the error list." + :package-version '(flycheck . "0.16") + :group 'flycheck-faces) + +(defface flycheck-error-list-line-number + '((t)) + "Face for line numbers in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "0.16")) + +(defface flycheck-error-list-column-number + '((t)) + "Face for line numbers in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "0.16")) + +(defface flycheck-error-list-filename + '((t :inherit mode-line-buffer-id :bold nil)) + "Face for filenames in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "32")) + +(defface flycheck-error-list-id + '((t :inherit font-lock-type-face)) + "Face for the error ID in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "0.22")) + +(defface flycheck-error-list-id-with-explainer + '((t :inherit flycheck-error-list-id + :box (:style released-button))) + "Face for the error ID in the error list, for errors that have an explainer." + :group 'flycheck-faces + :package-version '(flycheck . "30")) + +(defface flycheck-error-list-checker-name + '((t :inherit font-lock-function-name-face)) + "Face for the syntax checker name in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "0.21")) + +(defface flycheck-error-list-error-message + '((t)) + "Face for the error message in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "33")) + +(defface flycheck-error-list-highlight + '((t :bold t)) + "Flycheck face to highlight errors in the error list." + :package-version '(flycheck . "0.15") + :group 'flycheck-faces) + +(defface flycheck-verify-select-checker + '((t :box (:style released-button))) + "Flycheck face for the 'select' button in the verify setup buffer." + :package-version '(flycheck . "32") + :group 'flycheck-faces) + +(defvar flycheck-command-map + (let ((map (make-sparse-keymap))) + (define-key map "c" #'flycheck-buffer) + (define-key map "C" #'flycheck-clear) + (define-key map (kbd "C-c") #'flycheck-compile) + (define-key map "n" #'flycheck-next-error) + (define-key map "p" #'flycheck-previous-error) + (define-key map "l" #'flycheck-list-errors) + (define-key map (kbd "C-w") #'flycheck-copy-errors-as-kill) + (define-key map "s" #'flycheck-select-checker) + (define-key map "?" #'flycheck-describe-checker) + (define-key map "h" #'flycheck-display-error-at-point) + (define-key map "e" #'flycheck-explain-error-at-point) + (define-key map "H" #'display-local-help) + (define-key map "i" #'flycheck-manual) + (define-key map "V" #'flycheck-version) + (define-key map "v" #'flycheck-verify-setup) + (define-key map "x" #'flycheck-disable-checker) + map) + "Keymap of Flycheck interactive commands.") + +(defcustom flycheck-keymap-prefix (kbd "C-c !") + "Prefix for key bindings of Flycheck. + +Changing this variable outside Customize does not have any +effect. To change the keymap prefix from Lisp, you need to +explicitly re-define the prefix key: + + (define-key flycheck-mode-map flycheck-keymap-prefix nil) + (setq flycheck-keymap-prefix (kbd \"C-c f\")) + (define-key flycheck-mode-map flycheck-keymap-prefix + flycheck-command-map) + +Please note that Flycheck's manual documents the default +keybindings. Changing this variable is at your own risk." + :group 'flycheck + :package-version '(flycheck . "0.19") + :type 'string + :risky t + :set + (lambda (variable key) + (when (and (boundp variable) (boundp 'flycheck-mode-map)) + (define-key flycheck-mode-map (symbol-value variable) nil) + (define-key flycheck-mode-map key flycheck-command-map)) + (set-default variable key))) + +(defcustom flycheck-mode-line '(:eval (flycheck-mode-line-status-text)) + "Mode line lighter for Flycheck. + +The value of this variable is a mode line template as in +`mode-line-format'. See Info Node `(elisp)Mode Line Format' for +more information. Note that it should contain a _single_ mode +line construct only. + +Customize this variable to change how Flycheck reports its status +in the mode line. You may use `flycheck-mode-line-status-text' +to obtain a human-readable status text, including an +error/warning count. + +You may also assemble your own status text. The current status +of Flycheck is available in `flycheck-last-status-change'. The +errors in the current buffer are stored in +`flycheck-current-errors', and the function +`flycheck-count-errors' may be used to obtain the number of +errors grouped by error level. + +Set this variable to nil to disable the mode line completely." + :group 'flycheck + :type 'sexp + :risky t + :package-version '(flycheck . "0.20")) + +(defcustom flycheck-mode-line-prefix "FlyC" + "Base mode line lighter for Flycheck. + +This will have an effect only with the default +`flycheck-mode-line'. + +If you've customized `flycheck-mode-line' then the customized +function must be updated to use this variable." + :group 'flycheck + :type 'string + :package-version '(flycheck . "26")) + +(defcustom flycheck-error-list-mode-line + `(,(propertized-buffer-identification "%12b") + " for buffer " + (:eval (flycheck-error-list-propertized-source-name)) + (:eval (flycheck-error-list-mode-line-filter-indicator))) + "Mode line construct for Flycheck error list. + +The value of this variable is a mode line template as in +`mode-line-format', to be used as +`mode-line-buffer-identification' in `flycheck-error-list-mode'. +See Info Node `(elisp)Mode Line Format' for more information. + +Customize this variable to change how the error list appears in +the mode line. The default shows the name of the buffer and the +name of the source buffer, i.e. the buffer whose errors are +currently listed." + :group 'flycheck + :type 'sexp + :risky t + :package-version '(flycheck . "0.20")) + +(defcustom flycheck-global-modes t + "Modes for which option `flycheck-mode' is turned on. + +If t, Flycheck Mode is turned on for all major modes. If a list, +Flycheck Mode is turned on for all `major-mode' symbols in that +list. If the `car' of the list is `not', Flycheck Mode is turned +on for all `major-mode' symbols _not_ in that list. If nil, +Flycheck Mode is never turned on by command +`global-flycheck-mode'. + +Note that Flycheck is never turned on for modes whose +`mode-class' property is `special' (see Info node `(elisp)Major +Mode Conventions'), regardless of the value of this option. + +Only has effect when variable `global-flycheck-mode' is non-nil." + :group 'flycheck + :type '(choice (const :tag "none" nil) + (const :tag "all" t) + (set :menu-tag "mode specific" :tag "modes" + :value (not) + (const :tag "Except" not) + (repeat :inline t (symbol :tag "mode")))) + :risky t + :package-version '(flycheck . "0.23")) + +;; Add built-in functions to our hooks, via `add-hook', to make sure that our +;; functions are really present, even if the variable was implicitly defined by +;; another call to `add-hook' that occurred before Flycheck was loaded. See +;; http://lists.gnu.org/archive/html/emacs-devel/2015-02/msg01271.html for why +;; we don't initialize the hook variables right away. We append our own +;; functions, because a user likely expects that their functions come first, +;; even if they added them before Flycheck was loaded. +(dolist (hook (list #'flycheck-locate-config-file-by-path + #'flycheck-locate-config-file-ancestor-directories + #'flycheck-locate-config-file-home)) + (add-hook 'flycheck-locate-config-file-functions hook 'append)) + +(add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append) + + +;;; Global Flycheck menu +(defvar flycheck-mode-menu-map + (easy-menu-create-menu + "Syntax Checking" + '(["Enable on-the-fly syntax checking" flycheck-mode + :style toggle :selected flycheck-mode + :enable (or flycheck-mode + ;; Don't let users toggle the mode if there is no syntax + ;; checker for this buffer + (seq-find #'flycheck-checker-supports-major-mode-p + flycheck-checkers))] + ["Check current buffer" flycheck-buffer flycheck-mode] + ["Clear errors in buffer" flycheck-clear t] + "---" + ["Go to next error" flycheck-next-error flycheck-mode] + ["Go to previous error" flycheck-previous-error flycheck-mode] + ["Show all errors" flycheck-list-errors flycheck-mode] + "---" + ["Copy messages at point" flycheck-copy-errors-as-kill + (flycheck-overlays-at (point))] + ["Explain error at point" flycheck-explain-error-at-point] + "---" + ["Select syntax checker" flycheck-select-checker flycheck-mode] + ["Disable syntax checker" flycheck-disable-checker flycheck-mode] + ["Set executable of syntax checker" flycheck-set-checker-executable + flycheck-mode] + "---" + ["Describe syntax checker" flycheck-describe-checker t] + ["Verify setup" flycheck-verify-setup t] + ["Show Flycheck version" flycheck-version t] + ["Read the Flycheck manual" flycheck-info t])) + "Menu of command `flycheck-mode'.") + +(easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking") + + +;;; Version information, manual and loading of Flycheck +(defun flycheck-version (&optional show-version) + "Get the Flycheck version as string. + +If called interactively or if SHOW-VERSION is non-nil, show the +version in the echo area and the messages buffer. + +The returned string includes both, the version from package.el +and the library version, if both a present and different. + +If the version number could not be determined, signal an error, +if called interactively, or if SHOW-VERSION is non-nil, otherwise +just return nil." + (interactive (list t)) + (let ((version (pkg-info-version-info 'flycheck))) + (when show-version + (message "Flycheck version: %s" version)) + version)) + +(defun flycheck-unload-function () + "Unload function for Flycheck." + (global-flycheck-mode -1) + (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map)) + (remove-hook 'kill-emacs-hook #'flycheck-global-teardown) + (setq find-function-regexp-alist + (assq-delete-all 'flycheck-checker find-function-regexp-alist))) + +;;;###autoload +(defun flycheck-manual () + "Open the Flycheck manual." + (interactive) + (browse-url "http://www.flycheck.org")) + +(define-obsolete-function-alias 'flycheck-info + 'flycheck-manual "Flycheck 26" "Open the Flycheck manual.") + + +;;; Utility functions +(defun flycheck-sexp-to-string (sexp) + "Convert SEXP to a string. + +Like `prin1-to-string' but ensure that the returned string +is loadable." + (let ((print-quoted t) + (print-length nil) + (print-level nil)) + (prin1-to-string sexp))) + +(defun flycheck-string-to-number-safe (string) + "Safely convert STRING to a number. + +If STRING is of string type and a numeric string, convert STRING +to a number and return it. Otherwise return nil." + (let ((number-re (rx string-start (one-or-more (any digit)) string-end))) + (when (and (stringp string) (string-match-p number-re string)) + (string-to-number string)))) + +(defun flycheck-string-or-nil-p (obj) + "Determine if OBJ is a string or nil." + (or (null obj) (stringp obj))) + +(defun flycheck-string-list-p (obj) + "Determine if OBJ is a list of strings." + (and (listp obj) (seq-every-p #'stringp obj))) + +(defun flycheck-string-or-string-list-p (obj) + "Determine if OBJ is a string or a list of strings." + (or (stringp obj) (flycheck-string-list-p obj))) + +(defun flycheck-symbol-list-p (obj) + "Determine if OBJ is a list of symbols." + (and (listp obj) (seq-every-p #'symbolp obj))) + +(defvar-local flycheck--file-truename-cache nil) + +(defun flycheck--file-truename (file) + "Memoize the result of `file-truename' on (directory-file-name FILE)." + ;; `file-truename' is slow, but alternatives are incomplete, so memoizing is + ;; our best bet. See https://github.com/flycheck/flycheck/pull/1698. + (unless flycheck--file-truename-cache + (setq-local flycheck--file-truename-cache (make-hash-table :test 'equal))) + (or (gethash file flycheck--file-truename-cache) + (puthash file (file-truename (directory-file-name file)) + flycheck--file-truename-cache))) + +(defun flycheck-same-files-p (file-a file-b) + "Determine whether FILE-A and FILE-B refer to the same file. + +Files are the same if (in the order checked) they are equal, or +if they resolve to the same canonical paths." + (or (string= file-a file-b) + (string= (flycheck--file-truename file-a) + (flycheck--file-truename file-b)))) + +(defvar-local flycheck-temporaries nil + "Temporary files and directories created by Flycheck.") + +(defun flycheck-temp-dir-system () + "Create a unique temporary directory. + +Use `flycheck-temp-prefix' as prefix, and add the directory to +`flycheck-temporaries'. + +Return the path of the directory" + (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory))) + (push tempdir flycheck-temporaries) + tempdir)) + +(defun flycheck-temp-file-system (filename &optional suffix) + "Create a temporary file named after FILENAME. + +If FILENAME is non-nil, this function creates a temporary +directory with `flycheck-temp-dir-system', and creates a file +with the same name as FILENAME in this directory. + +Otherwise this function creates a temporary file starting with +`flycheck-temp-prefix'. If present, SUFFIX is appended; +otherwise, a random suffix is used. The path of the file is +added to `flycheck-temporaries'. + +Return the path of the file." + (let ((tempfile (convert-standard-filename + (if filename + (expand-file-name (file-name-nondirectory filename) + (flycheck-temp-dir-system)) + (make-temp-file flycheck-temp-prefix nil suffix))))) + (push tempfile flycheck-temporaries) + tempfile)) + +(defun flycheck-temp-file-inplace (filename &optional suffix) + "Create an in-place copy of FILENAME. + +Prefix the file with `flycheck-temp-prefix' and add the path of +the file to `flycheck-temporaries'. + +If FILENAME is nil, fall back to `flycheck-temp-file-system' with +the specified SUFFIX. + +Return the path of the file." + (if filename + (let* ((tempname (format "%s_%s" + flycheck-temp-prefix + (file-name-nondirectory filename))) + (tempfile (convert-standard-filename + (expand-file-name tempname + (file-name-directory filename))))) + (push tempfile flycheck-temporaries) + tempfile) + (flycheck-temp-file-system filename suffix))) + +(defun flycheck-temp-directory (checker) + "Return the directory where CHECKER writes temporary files. + +Return nil if the CHECKER does not write temporary files." + (let ((args (flycheck-checker-arguments checker))) + (cond + ((memq 'source args) temporary-file-directory) + ((memq 'source-inplace args) + (if buffer-file-name (file-name-directory buffer-file-name) + temporary-file-directory)) + (t nil)))) + +(defun flycheck-temp-files-writable-p (checker) + "Whether CHECKER can write temporary files. + +If CHECKER has `source' or `source-inplace' in its `:command', +return whether flycheck has the permissions to create the +respective temporary files. + +Return t if CHECKER does not use temporary files." + (let ((dir (flycheck-temp-directory checker))) + (or (not dir) (file-writable-p dir)))) + +(defun flycheck-save-buffer-to-file (file-name) + "Save the contents of the current buffer to FILE-NAME." + (make-directory (file-name-directory file-name) t) + (let ((jka-compr-inhibit t)) + (write-region nil nil file-name nil 0))) + +(defun flycheck-save-buffer-to-temp (temp-file-fn) + "Save buffer to temp file returned by TEMP-FILE-FN. + +Return the name of the temporary file." + (let ((filename (funcall temp-file-fn (buffer-file-name)))) + ;; Do not flush short-lived temporary files onto disk + (let ((write-region-inhibit-fsync t)) + (flycheck-save-buffer-to-file filename)) + filename)) + +(defun flycheck-prepend-with-option (option items &optional prepend-fn) + "Prepend OPTION to each item in ITEMS, using PREPEND-FN. + +Prepend OPTION to each item in ITEMS. + +ITEMS is a list of strings to pass to the syntax checker. OPTION +is the option, as string. PREPEND-FN is a function called to +prepend OPTION to each item in ITEMS. It receives the option and +a single item from ITEMS as argument, and must return a string or +a list of strings with OPTION prepended to the item. If +PREPEND-FN is nil or omitted, use `list'. + +Return a list of strings where OPTION is prepended to each item +in ITEMS using PREPEND-FN. If PREPEND-FN returns a list, it is +spliced into the resulting list." + (unless (stringp option) + (error "Option %S is not a string" option)) + (unless prepend-fn + (setq prepend-fn #'list)) + (let ((prepend + (lambda (item) + (let ((result (funcall prepend-fn option item))) + (cond + ((and (listp result) (seq-every-p #'stringp result)) result) + ((stringp result) (list result)) + (t (error "Invalid result type for option: %S" result))))))) + (apply #'append (seq-map prepend items)))) + +(defun flycheck-find-in-buffer (pattern) + "Find PATTERN in the current buffer. + +Return the result of the first matching group of PATTERN, or nil, +if PATTERN did not match." + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (when (re-search-forward pattern nil 'no-error) + (match-string-no-properties 1))))) + +(defun flycheck-buffer-empty-p (&optional buffer) + "Check whether a BUFFER is empty, defaulting to the current one." + (= (buffer-size buffer) 0)) + +(defun flycheck-buffer-nonempty-p (&optional buffer) + "Check whether a BUFFER is nonempty, defaulting to the current one." + (> (buffer-size buffer) 0)) + +(defun flycheck-ephemeral-buffer-p () + "Determine whether the current buffer is an ephemeral buffer. + +See Info node `(elisp)Buffer Names' for information about +ephemeral buffers." + (string-prefix-p " " (buffer-name))) + +(defun flycheck-encrypted-buffer-p () + "Determine whether the current buffer is an encrypted file. + +See Info node `(epa)Top' for Emacs' interface to encrypted +files." + ;; The EPA file handler sets this variable locally to remember the recipients + ;; of the encrypted file for re-encryption. Hence, a local binding of this + ;; variable is a good indication that the buffer is encrypted. I haven't + ;; found any better indicator anyway. + (local-variable-p 'epa-file-encrypt-to)) + +(defun flycheck-autoloads-file-p () + "Determine whether the current buffer is an autoloads file. + +Autoloads are generated by package.el during installation." + (string-suffix-p "-autoloads.el" (buffer-name))) + +(defun flycheck-in-user-emacs-directory-p (filename) + "Whether FILENAME is in `user-emacs-directory'." + (string-prefix-p (file-name-as-directory + (flycheck--file-truename user-emacs-directory)) + (flycheck--file-truename filename))) + +(defun flycheck-safe-delete (file-or-dir) + "Safely delete FILE-OR-DIR." + (ignore-errors + (if (file-directory-p file-or-dir) + (delete-directory file-or-dir 'recursive) + (delete-file file-or-dir)))) + +(defun flycheck-safe-delete-temporaries () + "Safely delete all temp files and directories of Flycheck. + +Safely delete all files and directories listed in +`flycheck-temporaries' and set the variable's value to nil." + (seq-do #'flycheck-safe-delete flycheck-temporaries) + (setq flycheck-temporaries nil)) + +(defun flycheck-rx-file-name (form) + "Translate the `(file-name)' FORM into a regular expression." + (let ((body (or (cdr form) '((minimal-match + (one-or-more not-newline)))))) + (rx-to-string `(group-n 1 ,@body) t))) + +(defun flycheck-rx-message (form) + "Translate the `(message)' FORM into a regular expression." + (let ((body (or (cdr form) '((one-or-more not-newline))))) + (rx-to-string `(group-n 4 ,@body) t))) + +(defun flycheck-rx-id (form) + "Translate the `(id)' FORM into a regular expression." + (rx-to-string `(group-n 5 ,@(cdr form)) t)) + +(defun flycheck-rx-to-string (form &optional no-group) + "Like `rx-to-string' for FORM, but with special keywords: + +`line' + matches the initial line number. + +`column' + matches the initial column number. + +`end-line' + matches the final line number. + +`end-column' + matches the final column number (exclusive). + + +`(file-name SEXP ...)' + matches the file name. SEXP describes the file name. If no + SEXP is given, use a default body of `(minimal-match + (one-or-more not-newline))'. + +`(message SEXP ...)' + matches the message. SEXP constitutes the body of the + message. If no SEXP is given, use a default body + of `(one-or-more not-newline)'. + +`(id SEXP ...)' + matches an error ID. SEXP describes the ID. + +NO-GROUP is passed to `rx-to-string'. + +See `rx' for a complete list of all built-in `rx' forms." + (let ((rx-constituents + (append + `((file-name flycheck-rx-file-name 0 nil) ;; group 1 + (line . ,(rx (group-n 2 (one-or-more digit)))) + (column . ,(rx (group-n 3 (one-or-more digit)))) + (message flycheck-rx-message 0 nil) ;; group 4 + (id flycheck-rx-id 0 nil) ;; group 5 + (end-line . ,(rx (group-n 6 (one-or-more digit)))) + (end-column . ,(rx (group-n 7 (one-or-more digit))))) + rx-constituents nil))) + (rx-to-string form no-group))) + +(defun flycheck-current-load-file () + "Get the source file currently being loaded. + +Always return the name of the corresponding source file, never +any byte-compiled file. + +Return nil, if the currently loaded file cannot be determined." + (-when-let* ((this-file (cond + (load-in-progress load-file-name) + ((bound-and-true-p byte-compile-current-file)) + (t (buffer-file-name)))) + ;; A best guess for the source file of a compiled library. Works + ;; well in most cases, and especially for ELPA packages + (source-file (concat (file-name-sans-extension this-file) + ".el"))) + (when (file-exists-p source-file) + source-file))) + +(defun flycheck-module-root-directory (module &optional file-name) + "Get the root directory for a MODULE in FILE-NAME. + +MODULE is a qualified module name, either a string with +components separated by a dot, or as list of components. +FILE-NAME is the name of the file or directory containing the +module as string. When nil or omitted, defaults to the return +value of function `buffer-file-name'. + +Return the root directory of the module, that is, the directory, +from which FILE-NAME can be reached by descending directories +along each part of MODULE. + +If the MODULE name does not match the directory hierarchy upwards +from FILE-NAME, return the directory containing FILE-NAME. When +FILE-NAME is nil, return `default-directory'." + (let ((file-name (or file-name (buffer-file-name))) + (module-components (if (stringp module) + (split-string module (rx ".")) + (copy-sequence module)))) + (if (and module-components file-name) + (let ((parts (nreverse module-components)) + (base-directory (directory-file-name + (file-name-sans-extension file-name)))) + (while (and parts + (string= (file-name-nondirectory base-directory) + (car parts))) + (pop parts) + (setq base-directory (directory-file-name + (file-name-directory base-directory)))) + (file-name-as-directory base-directory)) + (if file-name + (file-name-directory file-name) + (expand-file-name default-directory))))) + +(cl-defstruct (flycheck-line-cache + (:constructor flycheck-line-cache-new)) + "Cache structure used to speed up `flycheck-goto-line'." + tick point line) + +(defvar-local flycheck--line-cache nil + "Cache used to speed ip `flycheck-goto-line'.") + +(defsubst flycheck--init-line-cache () + "Initialize or reinitialize `flycheck--line-cache'." + (let ((tick (buffer-modified-tick))) + (if flycheck--line-cache + (unless (= (flycheck-line-cache-tick flycheck--line-cache) tick) + (setf (flycheck-line-cache-tick flycheck--line-cache) tick + (flycheck-line-cache-point flycheck--line-cache) 1 + (flycheck-line-cache-line flycheck--line-cache) 1)) + (setq-local flycheck--line-cache + (flycheck-line-cache-new :tick tick :point 1 :line 1))))) + +(defun flycheck-goto-line (line) + "Move point to beginning of line number LINE. + +This function assumes that the current buffer is not narrowed." + (flycheck--init-line-cache) + (goto-char (flycheck-line-cache-point flycheck--line-cache)) + (let ((delta (- line (flycheck-line-cache-line flycheck--line-cache)))) + (when (= 0 (forward-line delta)) + (setf (flycheck-line-cache-point flycheck--line-cache) (point)) + (setf (flycheck-line-cache-line flycheck--line-cache) line)))) + +(defun flycheck-line-column-to-position (line column) + "Return the point closest to LINE, COLUMN on line LINE. + +COLUMN is one-based." + (save-excursion + (flycheck-goto-line line) + (min (+ (point) (1- column)) (line-end-position)))) + +(defun flycheck-line-column-at-point () + "Return the line and column number at point." + (cons (line-number-at-pos) (1+ (- (point) (line-beginning-position))))) + +(defun flycheck-line-column-at-pos (pos) + "Return the line and column number at position POS. + +COLUMN is one-based." + (let ((inhibit-field-text-motion t)) + (save-excursion + (goto-char pos) + (flycheck-line-column-at-point)))) + + +;;; Minibuffer tools +(defvar flycheck-read-checker-history nil + "`completing-read' history of `flycheck-read-checker'.") + +(defun flycheck-completing-read (prompt candidates default &optional history) + "Read a value from the minibuffer. + +Use `flycheck-completing-read-function' to read input from the +minibuffer with completion. + +Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT. +HISTORY is passed to `flycheck-completing-read-function'. + +Note that `flycheck-completing-read-function' may return an empty +string instead of nil, even when \"\" isn't among the candidates. +See `completing-read' for more details." + (funcall flycheck-completing-read-function + prompt candidates nil 'require-match nil history default)) + +(defun flycheck-read-checker (prompt &optional default property candidates) + "Read a flycheck checker from minibuffer with PROMPT and DEFAULT. + +PROMPT is a string to show in the minibuffer as prompt. It +should end with a single space. DEFAULT is a symbol denoting the +default checker to use, if the user did not select any checker. +PROPERTY is a symbol denoting a syntax checker property. If +non-nil, only complete syntax checkers which have a non-nil value +for PROPERTY. CANDIDATES is an optional list of all syntax +checkers available for completion, defaulting to all defined +checkers. If given, PROPERTY is ignored. + +Return the checker as symbol, or DEFAULT if no checker was +chosen. If DEFAULT is nil and no checker was chosen, signal a +`user-error' if the underlying completion system does not provide +a default on its own." + (when (and default (not (flycheck-valid-checker-p default))) + (error "%S is no valid Flycheck checker" default)) + (let* ((candidates (seq-map #'symbol-name + (or candidates + (flycheck-defined-checkers property)))) + (default (and default (symbol-name default))) + (input (flycheck-completing-read + prompt candidates default + 'flycheck-read-checker-history))) + (when (string-empty-p input) + (unless default + (user-error "No syntax checker selected")) + (setq input default)) + (let ((checker (intern input))) + (unless (flycheck-valid-checker-p checker) + (error "%S is not a valid Flycheck syntax checker" checker)) + checker))) + +(defun flycheck-read-error-level (prompt) + "Read an error level from the user with PROMPT. + +Only offers level for which errors currently exist, in addition +to the default levels." + (let* ((levels (seq-map #'flycheck-error-level + (flycheck-error-list-current-errors))) + (levels-with-defaults (append '(info warning error) levels)) + (uniq-levels (seq-uniq levels-with-defaults)) + (level (flycheck-completing-read prompt uniq-levels nil))) + (when (string-empty-p level) (setq level nil)) + (and level (intern level)))) + + +;;; Checker API +(defun flycheck-defined-checkers (&optional property) + "Find all defined syntax checkers, optionally with PROPERTY. + +PROPERTY is a symbol. If given, only return syntax checkers with +a non-nil value for PROPERTY. + +The returned list is sorted alphapetically by the symbol name of +the syntax checkers." + (let (defined-checkers) + (mapatoms (lambda (symbol) + (when (and (flycheck-valid-checker-p symbol) + (or (null property) + (flycheck-checker-get symbol property))) + (push symbol defined-checkers)))) + (sort defined-checkers #'string<))) + +(defun flycheck-registered-checker-p (checker) + "Determine whether CHECKER is registered. + +A checker is registered if it is contained in +`flycheck-checkers'." + (and (flycheck-valid-checker-p checker) + (memq checker flycheck-checkers))) + +(defun flycheck-disabled-checker-p (checker) + "Determine whether CHECKER is disabled, manually or automatically." + (or (flycheck-manually-disabled-checker-p checker) + (flycheck-automatically-disabled-checker-p checker))) + +(defun flycheck-manually-disabled-checker-p (checker) + "Determine whether CHECKER has been manually disabled. + +A checker has been manually disabled if it is contained in +`flycheck-disabled-checkers'." + (memq checker flycheck-disabled-checkers)) + +(defun flycheck-automatically-disabled-checker-p (checker) + "Determine whether CHECKER has been automatically disabled. + +A checker has been automatically disabled if it is contained in +`flycheck--automatically-disabled-checkers'." + (memq checker flycheck--automatically-disabled-checkers)) + + +;;; Generic syntax checkers +(defconst flycheck-generic-checker-version 2 + "The internal version of generic syntax checker declarations. + +Flycheck will not use syntax checkers whose generic version is +less than this constant.") + +(defsubst flycheck--checker-property-name (property) + "Return the SYMBOL property for checker PROPERTY." + (intern (concat "flycheck-" (symbol-name property)))) + +(defun flycheck-checker-get (checker property) + "Get the value of CHECKER's PROPERTY." + (get checker (flycheck--checker-property-name property))) + +(gv-define-setter flycheck-checker-get (value checker property) + `(setf (get ,checker (flycheck--checker-property-name ,property)) ,value)) + +(defun flycheck-validate-next-checker (next &optional strict) + "Validate NEXT checker. + +With STRICT non-nil, also check whether the syntax checker and +the error level in NEXT are valid. Otherwise just check whether +these are symbols. + +Signal an error if NEXT is not a valid entry for +`:next-checkers'." + (when (symbolp next) + (setq next (cons t next))) + (pcase next + (`(,level . ,checker) + (if strict + (progn + (unless (or (eq level t) (flycheck-error-level-p level)) + (error "%S is not a valid Flycheck error level" level)) + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid Flycheck syntax checker" checker))) + (unless (symbolp level) + (error "Error level %S must be a symbol" level)) + (unless (symbolp checker) + (error "Checker %S must be a symbol" checker)))) + (_ (error "%S must be a symbol or cons cell" next))) + t) + +(defun flycheck-define-generic-checker (symbol docstring &rest properties) + "Define SYMBOL as generic syntax checker. + +Any syntax checker defined with this macro is eligible for manual +syntax checker selection with `flycheck-select-checker'. To make +the new syntax checker available for automatic selection, it must +be registered in `flycheck-checkers'. + +DOCSTRING is the documentation of the syntax checker, for +`flycheck-describe-checker'. The following PROPERTIES constitute +a generic syntax checker. Unless otherwise noted, all properties +are mandatory. + +`:start FUNCTION' + A function to start the syntax checker. + + FUNCTION shall take two arguments and return a context + object if the checker is started successfully. Otherwise it + shall signal an error. + + The first argument is the syntax checker being started. The + second is a callback function to report state changes to + Flycheck. The callback takes two arguments STATUS DATA, + where STATUS is a symbol denoting the syntax checker status + and DATA an optional argument with additional data for the + status report. See `flycheck-report-buffer-checker-status' + for more information about STATUS and DATA. + + FUNCTION may be synchronous or asynchronous, i.e. it may + call the given callback either immediately, or at some later + point (e.g. from a process sentinel). + + A syntax checker _must_ call CALLBACK at least once with a + STATUS that finishes the current syntax checker. Otherwise + Flycheck gets stuck at the current syntax check with this + syntax checker. + + The context object returned by FUNCTION is passed to + `:interrupt'. + +`:interrupt FUNCTION' + A function to interrupt the syntax check. + + FUNCTION is called with the syntax checker and the context + object returned by the `:start' function and shall try to + interrupt the syntax check. The context may be nil, if the + syntax check is interrupted before actually started. + FUNCTION should handle this situation. + + If it cannot interrupt the syntax check, it may either + signal an error or silently ignore the attempt to interrupt + the syntax checker, depending on the severity of the + situation. + + If interrupting the syntax check failed, Flycheck will let + the syntax check continue, but ignore any status reports. + Notably, it won't highlight any errors reported by the + syntax check in the buffer. + + This property is optional. If omitted, Flycheck won't + attempt to interrupt syntax checks with this syntax checker, + and simply ignore their results. + +`:print-doc FUNCTION' + A function to print additional documentation into the Help + buffer of this checker. + + FUNCTION is called when creating the Help buffer for the + syntax checker, with the syntax checker as single argument, + after printing the name of the syntax checker and its modes + and predicate, but before printing DOCSTRING. It may insert + additional documentation into the current buffer. + + The call occurs within `with-help-window'. Hence + `standard-output' points to the current buffer, so you may + use `princ' and friends to add content. Also, the current + buffer is put into Help mode afterwards, which automatically + turns symbols into references, if possible. + + This property is optional. If omitted, no additional + documentation is printed for this syntax checker. + +:verify FUNCTION + A function to verify the checker for the current buffer. + + FUNCTION is called with the syntax checker as single + argument, and shall return a list of + `flycheck-verification-result' objects indicating whether + the syntax checker could be used in the current buffer, and + highlighting potential setup problems. + + This property is optional. If omitted, no additional + verification occurs for this syntax checker. It is however + absolutely recommended that you add a `:verify' function to + your syntax checker, because it will help users to spot + potential setup problems. + +`:modes MODES' + A major mode symbol or a list thereof, denoting major modes + to use this syntax checker in. + + This syntax checker will only be used in buffers whose + `major-mode' is contained in MODES. + + If `:predicate' is also given the syntax checker will only + be used in buffers for which the `:predicate' returns + non-nil. + +`:predicate FUNCTION' + A function to determine whether to use the syntax checker in + the current buffer. + + FUNCTION is called without arguments and shall return + non-nil if this syntax checker shall be used to check the + current buffer. Otherwise it shall return nil. + + If this checker has a `:working-directory' FUNCTION is + called with `default-directory' bound to the checker's + working directory. + + FUNCTION is only called in matching major modes. + + This property is optional. + +`:enabled FUNCTION' + A function to determine whether to use the syntax checker in + the current buffer. + + This property behaves as `:predicate', except that it's only + called the first time a syntax checker is to be used in a buffer. + + FUNCTION is called without arguments and shall return + non-nil if this syntax checker shall be used to check the + current buffer. Otherwise it shall return nil. + + If FUNCTION returns a non-nil value the checker is put in a + whitelist in `flycheck--automatically-enabled-checkers' to + prevent further invocations of `:enabled'. Otherwise it is + disabled via `flycheck--automatically-disabled-checkers' to + prevent any further use of it. + + If this checker has a `:working-directory' FUNCTION is + called with `default-directory' bound to the checker's + working directory. + + FUNCTION is only called in matching major modes. + + This property is optional. + +`:error-filter FUNCTION' + A function to filter the errors returned by this checker. + + FUNCTION is called with the list of `flycheck-error' objects + returned by the syntax checker and shall return another list + of `flycheck-error' objects, which is considered the final + result of this syntax checker. + + FUNCTION is free to add, remove or modify errors, whether in + place or by copying. + + This property is optional. The default filter is + `identity'. + +`:error-explainer FUNCTION' + A function to return an explanation text for errors + generated by this checker. + + FUNCTION is called with a `flycheck-error' object, in the + buffer of that error. It shall return an explanation + message for the error. + + The message can take any of the following forms: + - A string, which will be displayed to the user + - A function (likely a closure), which will be called with + `standard-output' set to a `flycheck-explain-error-mode' + buffer, and should write to it. + - A cons `(url . ,URL), indicating that the explanation can + be found online at URL. + - nil if there is no explanation for this error. + + This property is optional. + +`:next-checkers NEXT-CHECKERS' + A list denoting syntax checkers to apply after this syntax + checker, in what we call \"chaining\" of syntax checkers. + + Each ITEM is a cons cell `(LEVEL . CHECKER)'. CHECKER is a + syntax checker to run after this syntax checker. LEVEL is + an error level. CHECKER will only be used if there are no + current errors of at least LEVEL. LEVEL may also be t, in + which case CHECKER is used regardless of the current errors. + + ITEM may also be a syntax checker symbol, which is + equivalent to `(t . ITEM)'. + + Flycheck tries all items in order of declaration, and uses + the first whose LEVEL matches and whose CHECKER is + registered and can be used for the current buffer. + + This feature is typically used to apply more than one syntax + checker to a buffer. For instance, you might first use a + compiler to check a buffer for syntax and type errors, and + then run a linting tool that checks for insecure code, or + questionable style. + + This property is optional. If omitted, it defaults to the + nil, i.e. no other syntax checkers are applied after this + syntax checker. + +`:working-directory FUNCTION' + The value of `default-directory' when invoking `:start'. + + FUNCTION is a function taking the syntax checker as sole + argument. It shall return the absolute path to an existing + directory to use as `default-directory' for `:start' or + nil to fall back to the `default-directory' of the current + buffer. + + This property is optional. If omitted, invoke `:start' + from the `default-directory' of the buffer being checked. + +Signal an error, if any property has an invalid value." + (declare (indent 1) + (doc-string 2)) + (let ((start (plist-get properties :start)) + (interrupt (plist-get properties :interrupt)) + (print-doc (plist-get properties :print-doc)) + (modes (plist-get properties :modes)) + (predicate (plist-get properties :predicate)) + (verify (plist-get properties :verify)) + (enabled (plist-get properties :enabled)) + (filter (or (plist-get properties :error-filter) #'identity)) + (explainer (plist-get properties :error-explainer)) + (next-checkers (plist-get properties :next-checkers)) + (file (flycheck-current-load-file)) + (working-directory (plist-get properties :working-directory))) + + (unless (listp modes) + (setq modes (list modes))) + + (unless (functionp start) + (error ":start %S of syntax checker %s is not a function" start symbol)) + (unless (or (null interrupt) (functionp interrupt)) + (error ":interrupt %S of syntax checker %s is not a function" + interrupt symbol)) + (unless (or (null print-doc) (functionp print-doc)) + (error ":print-doc %S of syntax checker %s is not a function" + print-doc symbol)) + (unless (or (null verify) (functionp verify)) + (error ":verify %S of syntax checker %S is not a function" + verify symbol)) + (unless (or (null enabled) (functionp enabled)) + (error ":enabled %S of syntax checker %S is not a function" + enabled symbol)) + (unless modes + (error "Missing :modes in syntax checker %s" symbol)) + (dolist (mode modes) + (unless (symbolp mode) + (error "Invalid :modes %s in syntax checker %s, %s must be a symbol" + modes symbol mode))) + (unless (or (null predicate) (functionp predicate)) + (error ":predicate %S of syntax checker %s is not a function" + predicate symbol)) + (unless (functionp filter) + (error ":error-filter %S of syntax checker %s is not a function" + filter symbol)) + (unless (or (null explainer) (functionp explainer)) + (error ":error-explainer %S of syntax checker %S is not a function" + explainer symbol)) + (dolist (checker next-checkers) + (flycheck-validate-next-checker checker)) + + (let ((real-predicate + (and predicate + (lambda () + ;; Run predicate in the checker's default directory + (let ((default-directory + (flycheck-compute-working-directory symbol))) + (funcall predicate))))) + (real-enabled + (lambda () + (if (flycheck-valid-checker-p symbol) + (or (null enabled) + ;; Run enabled in the checker's default directory + (let ((default-directory + (flycheck-compute-working-directory symbol))) + (funcall enabled))) + (lwarn 'flycheck + :warning "%S is no valid Flycheck syntax checker. +Try to reinstall the package defining this syntax checker." symbol) + nil)))) + (pcase-dolist (`(,prop . ,value) + `((start . ,start) + (interrupt . ,interrupt) + (print-doc . ,print-doc) + (modes . ,modes) + (predicate . ,real-predicate) + (verify . ,verify) + (enabled . ,real-enabled) + (error-filter . ,filter) + (error-explainer . ,explainer) + (next-checkers . ,next-checkers) + (documentation . ,docstring) + (file . ,file) + (working-directory . ,working-directory))) + (setf (flycheck-checker-get symbol prop) value))) + + ;; Track the version, to avoid breakage if the internal format changes + (setf (flycheck-checker-get symbol 'generic-checker-version) + flycheck-generic-checker-version))) + +(defun flycheck-valid-checker-p (checker) + "Check whether a CHECKER is valid. + +A valid checker is a symbol defined as syntax checker with +`flycheck-define-checker'." + (and (symbolp checker) + (= (or (get checker 'flycheck-generic-checker-version) 0) + flycheck-generic-checker-version))) + +(defun flycheck-checker-supports-major-mode-p (checker &optional mode) + "Whether CHECKER supports the given major MODE. + +CHECKER is a syntax checker symbol and MODE a major mode symbol. +Look at the `modes' property of CHECKER to determine whether +CHECKER supports buffers in the given major MODE. + +MODE defaults to the value of `major-mode' if omitted or nil. + +Return non-nil if CHECKER supports MODE and nil otherwise." + (let ((mode (or mode major-mode))) + (memq mode (flycheck-checker-get checker 'modes)))) + +(define-obsolete-variable-alias 'flycheck-enabled-checkers + 'flycheck--automatically-enabled-checkers "32") + +(defvar flycheck--automatically-enabled-checkers nil + "Syntax checkers included in automatic selection. + +A list of Flycheck syntax checkers included in automatic +selection for the current buffer.") +(make-variable-buffer-local 'flycheck--automatically-enabled-checkers) + +(defun flycheck-may-enable-checker (checker) + "Whether a generic CHECKER may be enabled for current buffer. + +Return non-nil if CHECKER may be used for the current buffer, and +nil otherwise. The result of the `:enabled' check, if any, is +cached." + (and + ;; May only enable valid checkers + (flycheck-valid-checker-p checker) + ;; Don't run the :enabled check if the checker is already disabled… + (not (flycheck-disabled-checker-p checker)) + (or + ;; …or if we've already cached the result + (memq checker flycheck--automatically-enabled-checkers) + (let* ((enabled (flycheck-checker-get checker 'enabled)) + (may-enable (or (null enabled) (funcall enabled)))) + ;; Cache the result + (if may-enable + (cl-pushnew checker flycheck--automatically-enabled-checkers) + (cl-pushnew checker flycheck--automatically-disabled-checkers)) + may-enable)))) + +(defun flycheck-reset-enabled-checker (checker) + "Reset the `:enabled' test of CHECKER. + +Forget that CHECKER has been enabled or automatically disabled +from a previous `:enabled' test. The result of the `:enabled' +test is cached in `flycheck-may-enable-checker': if you wish to +test the `:enabled' predicate again, you must first reset its +state using this function." + (when (memq checker flycheck--automatically-disabled-checkers) + (setq flycheck--automatically-disabled-checkers + (remq checker flycheck--automatically-disabled-checkers))) + (when (memq checker flycheck--automatically-enabled-checkers) + (setq flycheck--automatically-enabled-checkers + (remq checker flycheck--automatically-enabled-checkers))) + (flycheck-buffer)) + +(defun flycheck-may-use-checker (checker) + "Whether a generic CHECKER may be used. + +Return non-nil if CHECKER may be used for the current buffer, and +nil otherwise." + (let ((predicate (flycheck-checker-get checker 'predicate))) + (and (flycheck-valid-checker-p checker) + (flycheck-checker-supports-major-mode-p checker) + (flycheck-may-enable-checker checker) + (or (null predicate) (funcall predicate))))) + +(defun flycheck-may-use-next-checker (next-checker) + "Determine whether NEXT-CHECKER may be used." + (when (symbolp next-checker) + (push t next-checker)) + (let ((level (car next-checker)) + (next-checker (cdr next-checker))) + (and (or (eq level t) + (flycheck-has-max-current-errors-p level)) + (flycheck-registered-checker-p next-checker) + (flycheck-may-use-checker next-checker)))) + + +;;; Help for generic syntax checkers +(define-button-type 'help-flycheck-checker-def + :supertype 'help-xref + 'help-function #'flycheck-goto-checker-definition + 'help-echo "mouse-1, RET: find Flycheck checker definition") + +(defconst flycheck-find-checker-regexp + (rx line-start (zero-or-more (syntax whitespace)) + "(" symbol-start + (or "flycheck-define-checker" "flycheck-define-command-checker") + symbol-end + (eval (list 'regexp find-function-space-re)) + (? "'") + symbol-start "%s" symbol-end + (or (syntax whitespace) line-end)) + "Regular expression to find a checker definition.") + +(add-to-list 'find-function-regexp-alist + '(flycheck-checker . flycheck-find-checker-regexp)) + +(defun flycheck-goto-checker-definition (checker file) + "Go to to the definition of CHECKER in FILE." + (let ((location (find-function-search-for-symbol + checker 'flycheck-checker file))) + (pop-to-buffer (car location)) + (if (cdr location) + (goto-char (cdr location)) + (message "Unable to find checker location in file")))) + +(defun flycheck-checker-at-point () + "Return the Flycheck checker found at or before point. + +Return nil if there is no checker." + (let ((symbol (variable-at-point 'any-symbol))) + (when (flycheck-valid-checker-p symbol) + symbol))) + +(defun flycheck-describe-checker (checker) + "Display the documentation of CHECKER. + +CHECKER is a checker symbol. + +Pop up a help buffer with the documentation of CHECKER." + (interactive + (let* ((enable-recursive-minibuffers t) + (default (or (flycheck-checker-at-point) + (ignore-errors (flycheck-get-checker-for-buffer)))) + (prompt (if default + (format "Describe syntax checker (default %s): " default) + "Describe syntax checker: "))) + (list (flycheck-read-checker prompt default)))) + (unless (flycheck-valid-checker-p checker) + (user-error "You didn't specify a Flycheck syntax checker")) + (let ((filename (flycheck-checker-get checker 'file)) + (modes (flycheck-checker-get checker 'modes)) + (predicate (flycheck-checker-get checker 'predicate)) + (print-doc (flycheck-checker-get checker 'print-doc)) + (next-checkers (flycheck-checker-get checker 'next-checkers)) + (help-xref-following + ;; Ensure that we don't reuse buffers like `flycheck-verify-checker', + ;; and that we don't error out if a `help-flycheck-checker-doc' button + ;; is added outside of a documentation window. + (and help-xref-following (eq major-mode 'help-mode)))) + (help-setup-xref (list #'flycheck-describe-checker checker) + (called-interactively-p 'interactive)) + (save-excursion + (with-help-window (help-buffer) + (princ (format "%s is a Flycheck syntax checker" checker)) + (when filename + (princ (format " in `%s'" (file-name-nondirectory filename))) + (with-current-buffer standard-output + (save-excursion + (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-flycheck-checker-def + checker filename)))) + (princ ".\n\n") + + (let ((modes-start (with-current-buffer standard-output (point-max)))) + ;; Track the start of the modes documentation, to properly re-fill + ;; it later + (princ " This syntax checker checks syntax in the major mode(s) ") + (princ (string-join + (seq-map (apply-partially #'format "`%s'") modes) + ", ")) + (when predicate + (princ ", and uses a custom predicate")) + (princ ".") + (when next-checkers + (princ " It runs the following checkers afterwards:")) + (with-current-buffer standard-output + (save-excursion + (fill-region-as-paragraph modes-start (point-max)))) + (princ "\n") + + ;; Print the list of next checkers + (when next-checkers + (princ "\n") + (let ((beg-checker-list (with-current-buffer standard-output + (point)))) + (dolist (next-checker next-checkers) + (if (symbolp next-checker) + (princ (format " * `%s'\n" next-checker)) + (princ (format " * `%s' (maximum level `%s')\n" + (cdr next-checker) (car next-checker))))) + ;; + (with-current-buffer standard-output + (save-excursion + (while (re-search-backward "`\\([^`']+\\)'" + beg-checker-list t) + (let ((checker (intern-soft (match-string 1)))) + (when (flycheck-valid-checker-p checker) + (help-xref-button 1 'help-flycheck-checker-doc + checker))))))))) + ;; Call the custom print-doc function of the checker, if present + (when print-doc + (funcall print-doc checker)) + ;; Ultimately, print the docstring + (princ "\nDocumentation:\n") + (princ (flycheck-checker-get checker 'documentation)))))) + + +;;; Syntax checker verification +(cl-defstruct (flycheck-verification-result + (:constructor flycheck-verification-result-new)) + "Structure for storing a single verification result. + +Slots: + +`label' + A label for this result, as string + +`message' + A message for this result, as string + +`face' + The face to use for the `message'. + + You can either use a face symbol, or a list of face symbols." + label message face) + +(defun flycheck-verify-generic-checker (checker) + "Verify a generic CHECKER in the current buffer. + +Return a list of `flycheck-verification-result' objects." + (let (results + (predicate (flycheck-checker-get checker 'predicate)) + (enabled (flycheck-checker-get checker 'enabled)) + (verify (flycheck-checker-get checker 'verify))) + (when enabled + (let ((result (funcall enabled))) + (push (flycheck-verification-result-new + :label (propertize "may enable" 'help-echo ":enable") + :message (if result "yes" "no") + :face (if result 'success '(bold warning))) + results))) + (when predicate + (let ((result (funcall predicate))) + (push (flycheck-verification-result-new + :label (propertize "may run" 'help-echo ":predicate") + :message (prin1-to-string (not (null result))) + :face (if result 'success '(bold warning))) + results))) + (append (nreverse results) + (and verify (funcall verify checker))))) + +(define-button-type 'help-flycheck-checker-doc + :supertype 'help-xref + 'help-function #'flycheck-describe-checker + 'help-echo "mouse-1, RET: describe Flycheck checker") + +(define-button-type 'flycheck-button + 'follow-link t + 'action (lambda (pos) + (apply (get-text-property pos 'flycheck-action) + (get-text-property pos 'flycheck-data)) + ;; Revert the verify-setup buffer since it is now stale + (revert-buffer)) + 'face 'flycheck-verify-select-checker) + +(define-button-type 'flycheck-checker-select + :supertype 'flycheck-button + 'flycheck-action (lambda (buffer checker) + (with-current-buffer buffer + (flycheck-select-checker checker))) + 'help-echo "mouse-1, RET: select this checker") + +(define-button-type 'flycheck-checker-enable + :supertype 'flycheck-button + 'flycheck-action (lambda (buffer checker) + (interactive) + (with-current-buffer buffer + (flycheck--toggle-checker checker t) + (flycheck-buffer))) + 'help-echo "mouse-1, RET: re-enable this checker in this buffer") + +(define-button-type 'flycheck-checker-reset-enabled + :supertype 'flycheck-button + 'flycheck-action (lambda (buffer checker) + (with-current-buffer buffer + (flycheck-reset-enabled-checker checker))) + 'help-echo "mouse-1, RET: try to re-enable this checker") + +(defun flycheck--verify-princ-checker (checker buffer + &optional with-mm with-select) + "Print verification result of CHECKER for BUFFER. + +When WITH-MM is given and non-nil, also include the major mode +into the verification results. + +When WITH-SELECT is non-nil, add a button to select this checker." + (princ " ") + (insert-button (symbol-name checker) + 'type 'help-flycheck-checker-doc + 'help-args (list checker)) + (cond + ((with-current-buffer buffer + (flycheck-manually-disabled-checker-p checker)) + (insert (propertize " (manually disabled) " 'face '(bold error))) + (insert-text-button "enable" + 'type 'flycheck-checker-enable + 'flycheck-data (list buffer checker))) + ((with-current-buffer buffer + (flycheck-automatically-disabled-checker-p checker)) + (insert (propertize " (automatically disabled) " 'face '(bold error))) + (insert-text-button "reset" + 'type 'flycheck-checker-reset-enabled + 'flycheck-data (list buffer checker)))) + (when (eq checker (buffer-local-value 'flycheck-checker buffer)) + (insert (propertize " (explicitly selected)" 'face 'bold))) + (when with-select + (princ " ") + (insert-text-button "select" + 'type 'flycheck-checker-select + 'flycheck-data (list buffer checker))) + (princ "\n") + (let ((results (with-current-buffer buffer + (append (flycheck-verify-generic-checker checker) + (flycheck--verify-next-checkers checker))))) + (when with-mm + (with-current-buffer buffer + (let ((message-and-face + (if (flycheck-checker-supports-major-mode-p checker) + (cons (format "`%s' supported" major-mode) 'success) + (cons (format "`%s' not supported" major-mode) 'error)))) + (push (flycheck-verification-result-new + :label "major mode" + :message (car message-and-face) + :face (cdr message-and-face)) + results)))) + (let* ((label-length + (seq-max (mapcar + (lambda (res) + (length (flycheck-verification-result-label res))) + results))) + (message-column (+ 8 label-length))) + (dolist (result results) + (princ " - ") + (princ (flycheck-verification-result-label result)) + (princ ": ") + (princ (make-string (- message-column (current-column)) ?\ )) + (let ((message (flycheck-verification-result-message result)) + (face (flycheck-verification-result-face result))) + ;; If face is nil, using propertize erases the face already contained + ;; by the message. We don't want that, since this would remove the + ;; button face from the checker chain result. + (insert (if face (propertize message 'face face) message))) + (princ "\n")))) + (princ "\n")) + +(defun flycheck--get-next-checker-symbol (next) + "Get the checker symmbol of NEXT checker. + +NEXT should be either a cons (NEXT-CHECKER . LEVEL) or a +symbol." + (if (consp next) (cdr next) next)) + +(defun flycheck-get-next-checkers (checker) + "Return the immediate next checkers of CHECKER. + +This is a list of checker symbols. The error levels of the +`:next-checker' property are ignored." + (mapcar #'flycheck--get-next-checker-symbol + (flycheck-checker-get checker 'next-checkers))) + +(defun flycheck-all-next-checkers (checker) + "Return all checkers that may follow CHECKER. + +Return the transitive closure of the next-checker relation. The +return value is a list of checkers, not including CHECKER." + (let ((next-checkers) + (visited) + (queue (list checker))) + (while queue + (let ((c (pop queue))) + (push c visited) + (dolist (n (flycheck-get-next-checkers c)) + (push n next-checkers) + (unless (memq n visited) + (cl-pushnew n queue))))) + (seq-uniq next-checkers))) + +(defun flycheck--verify-next-checkers (checker) + "Return a verification result for the next checkers of CHECKER." + (-when-let (next (flycheck-get-next-checkers checker)) + (list + (flycheck-verification-result-new + :label "next checkers" + ;; We use `make-text-button' to preserve the button properties in the + ;; string + :message (mapconcat + (lambda (checker) + (make-text-button (symbol-name checker) nil + 'type 'help-flycheck-checker-doc + 'help-args (list checker))) + next + ", "))))) + +(defun flycheck--verify-print-header (desc buffer) + "Print a title with DESC for BUFFER in the current buffer. + +DESC is an arbitrary string containing a description, and BUFFER +is the buffer being verified. The name and the major mode mode +of BUFFER are printed. + +DESC and information about BUFFER are printed in the current +buffer." + (princ desc) + (insert (propertize (buffer-name buffer) 'face 'bold)) + (princ " in ") + (let ((mode (buffer-local-value 'major-mode buffer))) + (insert-button (symbol-name mode) + 'type 'help-function + 'help-args (list mode))) + (princ ":\n\n")) + +(defun flycheck--verify-print-footer (buffer) + "Print a footer for BUFFER in the current buffer. + +BUFFER is the buffer being verified." + (princ "Flycheck Mode is ") + (let ((enabled (buffer-local-value 'flycheck-mode buffer))) + (insert (propertize (if enabled "enabled" "disabled") + 'face (if enabled 'success '(warning bold))))) + (princ + (with-current-buffer buffer + ;; Use key binding state in the verified buffer to print the help. + (substitute-command-keys + ". Use \\[universal-argument] \\[flycheck-disable-checker] \ +to enable disabled checkers."))) + (save-excursion + (let ((end (point))) + (backward-paragraph) + (fill-region-as-paragraph (point) end))) + + (princ "\n\n--------------------\n\n") + (princ (format "Flycheck version: %s\n" (flycheck-version))) + (princ (format "Emacs version: %s\n" emacs-version)) + (princ (format "System: %s\n" system-configuration)) + (princ (format "Window system: %S\n" window-system))) + +(define-derived-mode flycheck-verify-mode help-mode + "Flycheck verification" + "Major mode to display Flycheck verification results." + ;; `help-mode-finish' will restore `buffer-read-only' + (setq buffer-read-only nil)) + +(defun flycheck-verify-checker (checker) + "Check whether a CHECKER can be used in this buffer. + +Show a buffer listing possible problems that prevent CHECKER from +being used for the current buffer. + +Note: Do not use this function to check whether a syntax checker +is applicable from Emacs Lisp code. Use +`flycheck-may-use-checker' instead." + (interactive (list (flycheck-read-checker "Checker to verify: "))) + (unless (flycheck-valid-checker-p checker) + (user-error "%s is not a syntax checker" checker)) + + ;; Save the buffer to make sure that all predicates are good + ;; FIXME: this may be surprising to users, with unintended side-effects. + (when (and (buffer-file-name) (buffer-modified-p)) + (save-buffer)) + + (let ((buffer (current-buffer))) + (with-help-window "*Flycheck checker*" + (with-current-buffer standard-output + (flycheck-verify-mode) + (flycheck--verify-print-header "Syntax checker in buffer " buffer) + (flycheck--verify-princ-checker checker buffer 'with-mm) + (if (with-current-buffer buffer (flycheck-may-use-checker checker)) + (insert (propertize + "Flycheck can use this syntax checker for this buffer.\n" + 'face 'success)) + (insert (propertize + "Flycheck cannot use this syntax checker for this buffer.\n" + 'face 'error))) + (insert "\n") + (flycheck--verify-print-footer buffer))))) + +(defun flycheck-verify-setup () + "Check whether Flycheck can be used in this buffer. + +Display a new buffer listing all syntax checkers that could be +applicable in the current buffer. For each syntax checkers, +possible problems are shown." + (interactive) + ;; Save to make sure checkers that only work on saved buffers will pass the + ;; verification + (when (and (buffer-file-name) (buffer-modified-p)) + (save-buffer)) + + (let* ((buffer (current-buffer)) + (first-checker (flycheck-get-checker-for-buffer)) + (valid-checkers + (remq first-checker + (seq-filter #'flycheck-may-use-checker flycheck-checkers))) + (valid-next-checkers + (when first-checker + (seq-intersection valid-checkers + (flycheck-all-next-checkers first-checker)))) + (valid-remaining (seq-difference valid-checkers valid-next-checkers)) + (other-checkers + (seq-difference (seq-filter #'flycheck-checker-supports-major-mode-p + flycheck-checkers) + (cons first-checker valid-checkers)))) + + ;; Print all applicable checkers for this buffer + (with-help-window "*Flycheck checkers*" + (with-current-buffer standard-output + (flycheck-verify-mode) + + (flycheck--verify-print-header "Syntax checkers for buffer " buffer) + + (if first-checker + (progn + (princ "First checker to run:\n\n") + (flycheck--verify-princ-checker first-checker buffer)) + (insert (propertize + "No checker to run in this buffer.\n\n" + 'face '(bold error)))) + + (when valid-next-checkers + (princ + "Checkers that may run as part of the first checker's chain:\n\n") + (dolist (checker valid-next-checkers) + (flycheck--verify-princ-checker checker buffer))) + + (when valid-remaining + (princ "Checkers that could run if selected:\n\n") + (dolist (checker valid-remaining) + (flycheck--verify-princ-checker checker buffer nil 'with-select))) + + (when other-checkers + (princ + "Checkers that are compatible with this mode, \ +but will not run until properly configured:\n\n") + (dolist (checker other-checkers) + (flycheck--verify-princ-checker checker buffer))) + + ;; If we have no checkers at all, that's worth mentioning + (unless (or first-checker valid-checkers other-checkers) + (insert (propertize + "No checkers are available for this buffer.\n\n" + 'face '(bold error)))) + + (let ((unregistered-checkers + (seq-difference (flycheck-defined-checkers) flycheck-checkers))) + (when unregistered-checkers + (insert (propertize + "The following syntax checkers are not registered:\n" + 'face '(bold warning))) + (dolist (checker unregistered-checkers) + (princ " - ") + (princ checker) + (princ "\n")) + (princ + "Try adding these syntax checkers to `flycheck-checkers'.\n\n"))) + + (flycheck--verify-print-footer buffer) + + (setq-local revert-buffer-function + (lambda (_ignore-auto _noconfirm) + (with-current-buffer buffer (flycheck-verify-setup)))))))) + + +;;; Predicates for generic syntax checkers +(defun flycheck-buffer-saved-p (&optional buffer) + "Determine whether BUFFER is saved to a file. + +BUFFER is the buffer to check. If omitted or nil, use the +current buffer as BUFFER. + +Return non-nil if the BUFFER is backed by a file, and not +modified, or nil otherwise." + (let ((file-name (buffer-file-name buffer))) + (and file-name (file-exists-p file-name) (not (buffer-modified-p buffer))))) + + +;;; Extending generic checkers +(defun flycheck-remove-next-checker (checker next) + "After CHECKER remove a NEXT checker. + +CHECKER is a syntax checker symbol, from which to remove NEXT +checker. + +NEXT is a cons or a symbol, as documented in +`flycheck-add-next-checker'." + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid syntax checker" checker)) + (let* ((next-symbol (flycheck--get-next-checker-symbol next))) + (setf + (flycheck-checker-get checker 'next-checkers) + (seq-remove + (lambda (next) (eq (flycheck--get-next-checker-symbol next) next-symbol)) + (flycheck-checker-get checker 'next-checkers))))) + +(defun flycheck-add-next-checker (checker next &optional append) + "After CHECKER add a NEXT checker. + +CHECKER is a syntax checker symbol, to which to add NEXT checker. + +NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'. NEXT-CHECKER is a +symbol denoting the syntax checker to run after CHECKER. LEVEL +is an error level. NEXT-CHECKER will only be used if there is no +current error whose level is more severe than LEVEL. LEVEL may +also be t, in which case NEXT-CHECKER is used regardless of the +current errors. + +NEXT can also be a syntax checker symbol only, which is +equivalent to `(t . NEXT)'. + +NEXT-CHECKER is prepended before other next checkers, unless +APPEND is non-nil." + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid syntax checker" checker)) + (flycheck-validate-next-checker next 'strict) + (flycheck-remove-next-checker checker next) + (let ((next-checkers (flycheck-checker-get checker 'next-checkers))) + (setf (flycheck-checker-get checker 'next-checkers) + (if append (append next-checkers (list next)) + (cons next next-checkers))))) + +(defun flycheck-add-mode (checker mode) + "To CHECKER add a new major MODE. + +CHECKER and MODE are symbols denoting a syntax checker and a +major mode respectively. + +Add MODE to the `:modes' property of CHECKER, so that CHECKER +will be used in buffers with MODE." + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid syntax checker" checker)) + (unless (symbolp mode) + (error "%s is not a symbol" mode)) + (push mode (flycheck-checker-get checker 'modes))) + + +;;; Generic syntax checks +(cl-defstruct (flycheck-syntax-check + (:constructor flycheck-syntax-check-new)) + "Structure for storing syntax check state. + +Slots: + +`buffer' + The buffer being checked. + +`checker' + The syntax checker being used. + +`context' + The context object. + +`working-directory' + Working directory for the syntax checker. Serve as a value for + `default-directory' for a checker." + buffer checker context working-directory) + +(defun flycheck-syntax-check-start (syntax-check callback) + "Start a SYNTAX-CHECK with CALLBACK." + (let ((checker (flycheck-syntax-check-checker syntax-check)) + (default-directory + (flycheck-syntax-check-working-directory syntax-check))) + (setf (flycheck-syntax-check-context syntax-check) + (funcall (flycheck-checker-get checker 'start) checker callback)))) + +(defun flycheck-syntax-check-interrupt (syntax-check) + "Interrupt a SYNTAX-CHECK." + (let* ((checker (flycheck-syntax-check-checker syntax-check)) + (interrupt-fn (flycheck-checker-get checker 'interrupt)) + (context (flycheck-syntax-check-context syntax-check))) + (when interrupt-fn + (funcall interrupt-fn checker context)))) + + +;;; Syntax checking mode + +(defvar flycheck-mode-map + (let ((map (make-sparse-keymap))) + (define-key map flycheck-keymap-prefix flycheck-command-map) + ;; We place the menu under a custom menu key. Since this menu key is not + ;; present in the menu of the global map, no top-level menu entry is added + ;; to the global menu bar. However, it still appears on the mode line + ;; lighter. + (define-key map [menu-bar flycheck] flycheck-mode-menu-map) + map) + "Keymap of command `flycheck-mode'.") + +(defvar-local flycheck-old-next-error-function nil + "Remember the old `next-error-function'.") + +(defconst flycheck-hooks-alist + '( + ;; Handle events that may start automatic syntax checks + (after-save-hook . flycheck-handle-save) + (after-change-functions . flycheck-handle-change) + ;; Handle events that may triggered pending deferred checks + (window-configuration-change-hook . flycheck-perform-deferred-syntax-check) + (post-command-hook . flycheck-perform-deferred-syntax-check) + ;; Teardown Flycheck whenever the buffer state is about to get lost, to + ;; clean up temporary files and directories. + (kill-buffer-hook . flycheck-teardown) + (change-major-mode-hook . flycheck-teardown) + (before-revert-hook . flycheck-teardown) + ;; Update the error list if necessary + (post-command-hook . flycheck-error-list-update-source) + (post-command-hook . flycheck-error-list-highlight-errors) + ;; Display errors. Show errors at point after commands (like movements) and + ;; when Emacs gets focus. Cancel the display timer when Emacs looses focus + ;; (as there's no need to display errors if the user can't see them), and + ;; hide the error buffer (for large error messages) if necessary. Note that + ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined + ;; hooks are perfectly ok we don't need a version guard here. They'll just + ;; not work silently. + (post-command-hook . flycheck-maybe-display-error-at-point-soon) + (focus-in-hook . flycheck-display-error-at-point-soon) + (focus-out-hook . flycheck-cancel-error-display-error-at-point-timer) + (post-command-hook . flycheck-hide-error-buffer) + ;; Immediately show error popups when navigating to an error + (next-error-hook . flycheck-display-error-at-point)) + "Hooks which Flycheck needs to hook in. + +The `car' of each pair is a hook variable, the `cdr' a function +to be added or removed from the hook variable if Flycheck mode is +enabled and disabled respectively.") + +;;;###autoload +(define-minor-mode flycheck-mode + "Flycheck is a minor mode for on-the-fly syntax checking. + +In `flycheck-mode' the buffer is automatically syntax-checked +using the first suitable syntax checker from `flycheck-checkers'. +Use `flycheck-select-checker' to select a checker for the current +buffer manually. + +If you run into issues, use `\\[flycheck-verify-setup]' to get help. + +Flycheck supports many languages out of the box, and many +additional ones are available on MELPA. Adding new ones is very +easy. Complete documentation is available online at URL +`https://www.flycheck.org/en/latest/'. Please report issues and +request features at URL `https://github.com/flycheck/flycheck'. + +Flycheck displays its status in the mode line. In the default +configuration, it looks like this: + +`FlyC' This buffer has not been checked yet. +`FlyC-' Flycheck doesn't have a checker for this buffer. +`FlyC*' Flycheck is running. Expect results soon! +`FlyC:3|2' This buffer contains three warnings and two errors. + Use `\\[flycheck-list-errors]' to see the list. + +You may also see the following icons: +`FlyC!' The checker crashed. +`FlyC.' The last syntax check was manually interrupted. +`FlyC?' The checker did something unexpected, like exiting with 1 + but returning no errors. + +The following keybindings are available in `flycheck-mode': + +\\{flycheck-mode-map} +\(you can change the prefix by customizing +`flycheck-keymap-prefix') + +If called interactively, enable Flycheck mode if ARG is positive, +and disable it if ARG is zero or negative. If called from Lisp, +also enable the mode if ARG is omitted or nil, and toggle it if +ARG is ‘toggle’; disable the mode otherwise." + :init-value nil + :keymap flycheck-mode-map + :lighter flycheck-mode-line + :after-hook (flycheck-buffer-automatically 'mode-enabled 'force-deferred) + (cond + (flycheck-mode + (flycheck-clear) + + (pcase-dolist (`(,hook . ,fn) (reverse flycheck-hooks-alist)) + (add-hook hook fn nil 'local)) + + (setq flycheck-old-next-error-function + (if flycheck-standard-error-navigation + next-error-function + :unset)) + (when flycheck-standard-error-navigation + (setq next-error-function #'flycheck-next-error-function)) + + ;; This hook must be added globally since otherwise we cannot + ;; detect a change from a buffer where Flycheck is enabled to a + ;; buffer where Flycheck is not enabled, and therefore cannot + ;; notice that there has been any change when the user switches + ;; back to the buffer where Flycheck is enabled. + (add-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch)) + (t + (unless (eq flycheck-old-next-error-function :unset) + (setq next-error-function flycheck-old-next-error-function)) + + (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist) + (remove-hook hook fn 'local)) + + (flycheck-teardown)))) + + +;;; Syntax checker selection for the current buffer +(defun flycheck-get-checker-for-buffer () + "Find the checker for the current buffer. + +Use the selected checker for the current buffer, if any, +otherwise search for the best checker from `flycheck-checkers'. + +Return checker if there is a checker for the current buffer, or +nil otherwise." + (if flycheck-checker + (when (flycheck-may-use-checker flycheck-checker) + flycheck-checker) + (seq-find #'flycheck-may-use-checker flycheck-checkers))) + +(defun flycheck-get-next-checker-for-buffer (checker) + "Get the checker to run after CHECKER for the current buffer." + (let ((next (seq-find #'flycheck-may-use-next-checker + (flycheck-checker-get checker 'next-checkers)))) + (when next + (if (symbolp next) next (cdr next))))) + +(defun flycheck-select-checker (checker) + "Select CHECKER for the current buffer. + +CHECKER is a syntax checker symbol (see `flycheck-checkers') or +nil. In the former case, use CHECKER for the current buffer, +otherwise deselect the current syntax checker (if any) and use +automatic checker selection via `flycheck-checkers'. + +If called interactively prompt for CHECKER. With prefix arg +deselect the current syntax checker and enable automatic +selection again. + +Set `flycheck-checker' to CHECKER and automatically start a new +syntax check if the syntax checker changed. + +CHECKER will be used, even if it is not contained in +`flycheck-checkers', or if it is disabled via +`flycheck-disabled-checkers'." + (interactive + (if current-prefix-arg + (list nil) + (list (flycheck-read-checker "Select checker: " + (flycheck-get-checker-for-buffer))))) + (when (not (eq checker flycheck-checker)) + (unless (or (not checker) (flycheck-may-use-checker checker)) + (flycheck-verify-checker checker) + (user-error "Can't use syntax checker %S in this buffer" checker)) + (setq flycheck-checker checker) + (when flycheck-mode + (flycheck-buffer)))) + +(defun flycheck--toggle-checker (checker enable) + "Enable or disable CHECKER for the current buffer. + +If ENABLE, re-enable CHECKER by removing it from the buffer-local +value of `flycheck-disabled-checkers'. Otherwise, add the syntax +checker to the buffer-local value of `flycheck-disabled-checkers'." + (cond + (enable + ;; We must use `remq' instead of `delq', because we must _not_ modify the + ;; list. Otherwise we could potentially modify the global default value, + ;; in case the list is the global default. + (when (memq checker flycheck-disabled-checkers) + (setq flycheck-disabled-checkers + (remq checker flycheck-disabled-checkers))) + (when (memq checker flycheck--automatically-disabled-checkers) + (setq flycheck--automatically-disabled-checkers + (remq checker flycheck--automatically-disabled-checkers)))) + (t (unless (memq checker flycheck-disabled-checkers) + (push checker flycheck-disabled-checkers))))) + +(defun flycheck-disable-checker (checker &optional enable) + "Interactively disable CHECKER for the current buffer. + +Prompt for a syntax checker to disable, and add the syntax +checker to the buffer-local value of +`flycheck-disabled-checkers'. + +With non-nil ENABLE or with prefix arg, prompt for a disabled +syntax checker and re-enable it by removing it from the +buffer-local value of `flycheck-disabled-checkers'." + (declare + (interactive-only "Directly set `flycheck-disabled-checkers' instead")) + (interactive + (let* ((enable current-prefix-arg) + (candidates (if enable + (append flycheck-disabled-checkers + flycheck--automatically-disabled-checkers) + flycheck-checkers)) + (prompt (if enable "Enable syntax checker: " + "Disable syntax checker: "))) + (when (and enable (not candidates)) + (user-error "No syntax checkers disabled in this buffer")) + (list (flycheck-read-checker prompt nil nil candidates) enable))) + (unless checker + (user-error "No syntax checker given")) + (flycheck--toggle-checker checker enable) + (flycheck-buffer)) + + +;;; Syntax checks for the current buffer +(defvar-local flycheck-current-syntax-check nil + "The current syntax check in the this buffer.") +(put 'flycheck-current-syntax-check 'permanent-local t) + +(defun flycheck-start-current-syntax-check (checker) + "Start a syntax check in the current buffer with CHECKER. + +Set `flycheck-current-syntax-check' accordingly." + ;; Allocate the current syntax check *before* starting it. This allows for + ;; synchronous checks, which call the status callback immediately in their + ;; start function. + (let* ((check + (flycheck-syntax-check-new + :buffer (current-buffer) + :checker checker + :context nil + :working-directory (flycheck-compute-working-directory checker))) + (callback (flycheck-buffer-status-callback check))) + (setq flycheck-current-syntax-check check) + (flycheck-report-status 'running) + (flycheck-syntax-check-start check callback))) + +(defun flycheck-running-p () + "Determine whether a syntax check is running in the current buffer." + (not (null flycheck-current-syntax-check))) + +(defun flycheck-stop () + "Stop any ongoing syntax check in the current buffer." + (when (flycheck-running-p) + (flycheck-syntax-check-interrupt flycheck-current-syntax-check) + ;; Remove the current syntax check, to reset Flycheck into a non-running + ;; state, and to make `flycheck-report-buffer-checker-status' ignore any + ;; status reports from the current syntax check. + (setq flycheck-current-syntax-check nil) + (flycheck-report-status 'interrupted))) + +(defun flycheck-buffer-status-callback (syntax-check) + "Create a status callback for SYNTAX-CHECK in the current buffer." + (lambda (&rest args) + (apply #'flycheck-report-buffer-checker-status + syntax-check args))) + +(defun flycheck-buffer () + "Start checking syntax in the current buffer. + +Get a syntax checker for the current buffer with +`flycheck-get-checker-for-buffer', and start it." + (interactive) + (flycheck-clean-deferred-check) + (if flycheck-mode + (unless (flycheck-running-p) + ;; Clear error list and mark all overlays for deletion. We do not + ;; delete all overlays immediately to avoid excessive re-displays and + ;; flickering, if the same errors gets highlighted again after the check + ;; completed. + (run-hooks 'flycheck-before-syntax-check-hook) + (flycheck-clear-errors) + (flycheck-mark-all-overlays-for-deletion) + (condition-case err + (let* ((checker (flycheck-get-checker-for-buffer))) + (if checker + (flycheck-start-current-syntax-check checker) + (flycheck-clear) + (flycheck-report-status 'no-checker))) + (error + (flycheck-report-failed-syntax-check) + (signal (car err) (cdr err))))) + (user-error "Flycheck mode disabled"))) + +(defun flycheck-report-buffer-checker-status + (syntax-check status &optional data) + "In BUFFER, report a SYNTAX-CHECK STATUS with DATA. + +SYNTAX-CHECK is the `flycheck-syntax-check' which reported +STATUS. STATUS denotes the status of CHECKER, with an optional +DATA. STATUS may be one of the following symbols: + +`errored' + The syntax checker has errored. DATA is an optional error + message. + + This report finishes the current syntax check. + +`interrupted' + The syntax checker was interrupted. DATA is ignored. + + This report finishes the current syntax check. + +`finished' + The syntax checker has finished with a proper error report + for the current buffer. DATA is the (potentially empty) + list of `flycheck-error' objects reported by the syntax + check. + + This report finishes the current syntax check. + +`suspicious' + The syntax checker encountered a suspicious state, which the + user needs to be informed about. DATA is an optional + message. + +A syntax checker _must_ report a status at least once with any +symbol that finishes the current syntax checker. Otherwise +Flycheck gets stuck with the current syntax check. + +If CHECKER is not the currently used syntax checker in +`flycheck-current-syntax-check', the status report is largely +ignored. Notably, any errors reported by the checker are +discarded." + (let ((buffer (flycheck-syntax-check-buffer syntax-check))) + ;; Ignore the status report if the buffer is gone, or if this syntax check + ;; isn't the current one in buffer (which can happen if this is an old + ;; report of an interrupted syntax check, and a new syntax check was started + ;; since this check was interrupted) + (when (and (buffer-live-p buffer) + (eq syntax-check + (buffer-local-value 'flycheck-current-syntax-check buffer))) + (with-current-buffer buffer + (let ((checker (flycheck-syntax-check-checker syntax-check))) + (pcase status + ((or `errored `interrupted) + (flycheck-report-failed-syntax-check status) + (when (eq status 'errored) + ;; In case of error, show the error message + (message "Error from syntax checker %s: %s" + checker (or data "UNKNOWN!")))) + (`suspicious + (when flycheck-mode + (message "Suspicious state from syntax checker %s: %s" + checker (or data "UNKNOWN!"))) + (flycheck-report-status 'suspicious)) + (`finished + (when flycheck-mode + ;; Only report errors from the checker if Flycheck Mode is + ;; still enabled. + (flycheck-finish-current-syntax-check + data + (flycheck-syntax-check-working-directory syntax-check)))) + (_ + (error "Unknown status %s from syntax checker %s" + status checker)))))))) + +(defun flycheck-finish-current-syntax-check (errors working-dir) + "Finish the current syntax-check in the current buffer with ERRORS. + +ERRORS is a list of `flycheck-error' objects reported by the +current syntax check in `flycheck-current-syntax-check'. + +Report all ERRORS and potentially start any next syntax checkers. + +If the current syntax checker reported excessive errors, it is +disabled via `flycheck-disable-excessive-checker' for subsequent +syntax checks. + +Relative file names in ERRORS will be expanded relative to +WORKING-DIR." + (let* ((syntax-check flycheck-current-syntax-check) + (checker (flycheck-syntax-check-checker syntax-check)) + (errors (flycheck-relevant-errors + (flycheck-fill-and-expand-error-file-names + (flycheck-filter-errors + (flycheck-assert-error-list-p errors) checker) + working-dir)))) + (unless (flycheck-disable-excessive-checker checker errors) + (flycheck-report-current-errors errors)) + (let ((next-checker (flycheck-get-next-checker-for-buffer checker))) + (if next-checker + (flycheck-start-current-syntax-check next-checker) + (setq flycheck-current-syntax-check nil) + (flycheck-report-status 'finished) + ;; Delete overlays only after the very last checker has run, to avoid + ;; flickering on intermediate re-displays + (flycheck-delete-marked-overlays) + (flycheck-error-list-refresh) + (run-hooks 'flycheck-after-syntax-check-hook) + (when (eq (current-buffer) (window-buffer)) + (flycheck-display-error-at-point)) + ;; Immediately try to run any pending deferred syntax check, which + ;; were triggered by intermediate automatic check event, to make sure + ;; that we quickly refine outdated error information + (flycheck-perform-deferred-syntax-check))))) + +(defun flycheck-disable-excessive-checker (checker errors) + "Disable CHECKER if it reported excessive ERRORS. + +If ERRORS has more items than `flycheck-checker-error-threshold', +add CHECKER to `flycheck--automatically-disabled-checkers', and +show a warning. + +Return t when CHECKER was disabled, or nil otherwise." + (when (and flycheck-checker-error-threshold + (> (length errors) flycheck-checker-error-threshold)) + ;; Disable CHECKER for this buffer + ;; (`flycheck--automatically-disabled-checkers' is a local variable). + (lwarn '(flycheck syntax-checker) :warning + (substitute-command-keys + "Syntax checker %s reported too many errors (%s) and is disabled. +Use `\\[customize-variable] RET flycheck-checker-error-threshold' to +change the threshold or `\\[universal-argument] \ +\\[flycheck-disable-checker]' to re-enable the checker.") + checker (length errors)) + (push checker flycheck--automatically-disabled-checkers) + t)) + +(defun flycheck-clear (&optional shall-interrupt) + "Clear all errors in the current buffer. + +With prefix arg or SHALL-INTERRUPT non-nil, also interrupt the +current syntax check." + (interactive "P") + (when shall-interrupt + (flycheck-stop)) + (flycheck-delete-all-overlays) + (flycheck-clear-errors) + (flycheck-error-list-refresh) + (flycheck-hide-error-buffer)) + +(defun flycheck--empty-variables () + "Empty variables used by Flycheck." + (kill-local-variable 'flycheck--file-truename-cache) + (kill-local-variable 'flycheck--idle-trigger-timer) + (kill-local-variable 'flycheck--idle-trigger-conditions) + (kill-local-variable 'flycheck--last-error-display-tick)) + +(defun flycheck-teardown (&optional ignore-global) + "Teardown Flycheck in the current buffer. + +Completely clear the whole Flycheck state. Remove overlays, kill +running checks, and empty all variables used by Flycheck. + +Unless optional argument IGNORE-GLOBAL is non-nil, check to see +if no more Flycheck buffers remain (aside from the current +buffer), and if so then clean up global hooks." + (flycheck-safe-delete-temporaries) + (flycheck-stop) + (flycheck-clean-deferred-check) + (flycheck-clear) + (flycheck-cancel-error-display-error-at-point-timer) + (flycheck--clear-idle-trigger-timer) + (flycheck--empty-variables) + (unless (or ignore-global + (seq-some (lambda (buf) + (and (not (equal buf (current-buffer))) + (buffer-local-value 'flycheck-mode buf))) + (buffer-list))) + (flycheck-global-teardown 'ignore-local))) + + +;;; Automatic syntax checking in a buffer +(defun flycheck-may-check-automatically (&rest conditions) + "Determine whether the buffer may be checked under one of CONDITIONS. + +Read-only buffers may never be checked automatically. + +If CONDITIONS are given, determine whether syntax may be checked +under at least one of them, according to +`flycheck-check-syntax-automatically'." + (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p))) + (file-exists-p default-directory) + (or (not conditions) + (seq-some + (lambda (condition) + (memq condition flycheck-check-syntax-automatically)) + conditions)))) + +(defvar-local flycheck--idle-trigger-timer nil + "Timer used to trigger a syntax check after an idle delay.") + +(defvar-local flycheck--idle-trigger-conditions nil + "List of conditions under which an idle syntax check will be triggered. +This will be some subset of the allowable values for +`flycheck-check-syntax-automatically'. + +For example, if the user switches to a buffer and then makes an +edit, this list will have the values `idle-change' and +`idle-buffer-switch' in it, at least until the idle timer +expires.") + +(defun flycheck-buffer-automatically (&optional condition force-deferred) + "Automatically check syntax at CONDITION. + +Syntax is not checked if `flycheck-may-check-automatically' +returns nil for CONDITION. (CONDITION may be a single condition +or a list of them.) + +The syntax check is deferred if FORCE-DEFERRED is non-nil, or if +`flycheck-must-defer-check' returns t." + (when (and flycheck-mode (if (listp condition) + (apply #'flycheck-may-check-automatically + condition) + (flycheck-may-check-automatically condition))) + (flycheck--clear-idle-trigger-timer) + (setq flycheck--idle-trigger-conditions nil) + (if (or force-deferred (flycheck-must-defer-check)) + (flycheck-buffer-deferred) + (with-demoted-errors "Error while checking syntax automatically: %S" + (flycheck-buffer))))) + +(defun flycheck--clear-idle-trigger-timer () + "Clear the idle trigger timer." + (when flycheck--idle-trigger-timer + (cancel-timer flycheck--idle-trigger-timer) + (setq flycheck--idle-trigger-timer nil))) + +(defun flycheck--handle-idle-trigger (buffer) + "Run a syntax check in BUFFER if appropriate. +This function is called by `flycheck--idle-trigger-timer'." + (let ((current-buffer (current-buffer))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (unless (or flycheck-buffer-switch-check-intermediate-buffers + (eq buffer current-buffer)) + (setq flycheck--idle-trigger-conditions + (delq 'idle-buffer-switch + flycheck--idle-trigger-conditions))) + (when flycheck--idle-trigger-conditions + (flycheck-buffer-automatically flycheck--idle-trigger-conditions) + (setq flycheck--idle-trigger-conditions nil)))))) + +(defun flycheck-handle-change (beg end _len) + "Handle a buffer change between BEG and END. + +BEG and END mark the beginning and end of the change text. _LEN +is ignored. + +Start a syntax check if a new line has been inserted into the +buffer." + ;; Save and restore the match data, as recommended in (elisp)Change Hooks + (save-match-data + (when flycheck-mode + (if (string-match-p (rx "\n") (buffer-substring beg end)) + (flycheck-buffer-automatically 'new-line 'force-deferred) + (when (memq 'idle-change flycheck-check-syntax-automatically) + (flycheck--clear-idle-trigger-timer) + (cl-pushnew 'idle-change flycheck--idle-trigger-conditions) + (setq flycheck--idle-trigger-timer + (run-at-time flycheck-idle-change-delay nil + #'flycheck--handle-idle-trigger + (current-buffer)))))))) + +(defvar flycheck--last-buffer (current-buffer) + "The current buffer or the buffer that was previously current. +This is usually equal to the current buffer, unless the user just +switched buffers. After a buffer switch, it is the previous +buffer.") + +(defun flycheck-handle-buffer-switch () + "Handle a possible switch to another buffer. + +If a buffer switch actually happened, schedule a syntax check." + ;; Switching buffers here is weird, but unfortunately necessary. It + ;; turns out that `with-temp-buffer' triggers + ;; `buffer-list-update-hook' twice, and the value of + ;; `current-buffer' is bogus in one of those triggers (the one just + ;; after the temp buffer is killed). If we rely on the bogus value, + ;; Flycheck will think that the user is switching back and forth + ;; between different buffers during the `with-temp-buffer' call + ;; (note: two different normal buffers, not the current buffer and + ;; the temp buffer!), and that would trigger spurious syntax checks. + ;; It seems that reading (window-buffer) gets us the correct current + ;; buffer in all important real-life situations (although it doesn't + ;; necessarily catch uses of `set-buffer'). + (with-current-buffer (window-buffer) + (unless (or (equal flycheck--last-buffer (current-buffer)) + ;; Don't bother keeping track of changes to and from + ;; the minibuffer, as they will never require us to + ;; run a syntax check. + (minibufferp)) + (setq flycheck--last-buffer (current-buffer)) + (when (and flycheck-mode + (memq 'idle-buffer-switch flycheck-check-syntax-automatically)) + (flycheck--clear-idle-trigger-timer) + (cl-pushnew 'idle-buffer-switch flycheck--idle-trigger-conditions) + (setq flycheck--idle-trigger-timer + (run-at-time flycheck-idle-buffer-switch-delay nil + #'flycheck--handle-idle-trigger + (current-buffer))))))) + +(defun flycheck-handle-save () + "Handle a save of the buffer." + (flycheck-buffer-automatically 'save)) + + +;;; Deferred syntax checking +(defvar-local flycheck-deferred-syntax-check nil + "If non-nil, a deferred syntax check is pending.") + +(defun flycheck-must-defer-check () + "Determine whether the syntax check has to be deferred. + +A check has to be deferred if the buffer is not visible, or if the buffer is +currently being reverted. + +Return t if the check is to be deferred, or nil otherwise." + (or (not (get-buffer-window)) + ;; We defer the syntax check if Flycheck is already running, to + ;; immediately start a new syntax check after the current one finished, + ;; because the result of the current check will most likely be outdated by + ;; the time it is finished. + (flycheck-running-p) + ;; We must defer checks while a buffer is being reverted, to avoid race + ;; conditions while the buffer contents are being restored. + revert-buffer-in-progress-p)) + +(defun flycheck-deferred-check-p () + "Determine whether the current buffer has a deferred check. + +Return t if so, or nil otherwise." + flycheck-deferred-syntax-check) + +(defun flycheck-buffer-deferred () + "Defer syntax check for the current buffer." + (setq flycheck-deferred-syntax-check t)) + +(defun flycheck-clean-deferred-check () + "Clean a deferred syntax checking state." + (setq flycheck-deferred-syntax-check nil)) + +(defun flycheck-perform-deferred-syntax-check () + "Perform the deferred syntax check." + (when (flycheck-deferred-check-p) + (flycheck-clean-deferred-check) + (flycheck-buffer-automatically))) + + +;;; Syntax checking in all buffers +(defun flycheck-may-enable-mode () + "Determine whether Flycheck mode may be enabled. + +Flycheck mode is not enabled for + +- the minibuffer, +- `fundamental-mode' +- major modes whose `mode-class' property is `special', +- ephemeral buffers (see `flycheck-ephemeral-buffer-p'), +- encrypted buffers (see `flycheck-encrypted-buffer-p'), +- remote files (see `file-remote-p'), +- and major modes excluded by `flycheck-global-modes'. + +Return non-nil if Flycheck mode may be enabled, and nil +otherwise." + (and (pcase flycheck-global-modes + ;; Whether `major-mode' is disallowed by `flycheck-global-modes' + (`t t) + (`(not . ,modes) (not (memq major-mode modes))) + (modes (memq major-mode modes))) + (not (or (minibufferp) + (eq major-mode 'fundamental-mode) + (eq (get major-mode 'mode-class) 'special) + (flycheck-ephemeral-buffer-p) + (flycheck-encrypted-buffer-p) + (and (buffer-file-name) + (file-remote-p (buffer-file-name) 'method)))))) + +(defun flycheck-mode-on-safe () + "Enable command `flycheck-mode' if it is safe to do so. + +Command `flycheck-mode' is only enabled if +`flycheck-may-enable-mode' returns a non-nil result." + (when (flycheck-may-enable-mode) + (flycheck-mode))) + +;;;###autoload +(define-globalized-minor-mode global-flycheck-mode flycheck-mode + flycheck-mode-on-safe + :init-value nil + ;; Do not expose Global Flycheck Mode on customize interface, because the + ;; interaction between package.el and customize is currently broken. See + ;; https://github.com/flycheck/flycheck/issues/595 + + ;; :require 'flycheck :group + ;; 'flycheck + ) + +(defun flycheck-global-teardown (&optional ignore-local) + "Teardown Flycheck in all buffers. + +Completely clear the whole Flycheck state in all buffers, stop +all running checks, remove all temporary files, and empty all +variables of Flycheck. + +Also remove global hooks. (If optional argument IGNORE-LOCAL is +non-nil, then only do this and skip per-buffer teardown.)" + (unless ignore-local + (dolist (buffer (buffer-list)) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (when flycheck-mode + (flycheck-teardown 'ignore-global)))))) + (remove-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch)) + +;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any +;; pending temporary files. +(add-hook 'kill-emacs-hook #'flycheck-global-teardown) + + +;;; Errors from syntax checks +(cl-defstruct (flycheck-error + (:constructor nil) + (:constructor + flycheck-error-new + (&key + line column end-line end-column + buffer checker filename message level id group + &aux (-end-line end-line) (-end-column end-column))) + (:constructor + flycheck-error-new-at + (line + column + &optional level message + &key end-line end-column checker id group + (filename (buffer-file-name)) (buffer (current-buffer)) + &aux (-end-line end-line) (-end-column end-column))) + (:constructor + flycheck-error-new-at-pos + (pos + &optional level message + &key end-pos checker id group + (filename (buffer-file-name)) (buffer (current-buffer)) + &aux + ((line . column) + (if pos (flycheck-line-column-at-pos pos) + '(nil . nil))) + ((-end-line . -end-column) + (if end-pos (flycheck-line-column-at-pos end-pos) + '(nil . nil)))))) + "Structure representing an error reported by a syntax checker. +Slots: + +`buffer' + The buffer that the error was reported for, as buffer object. + +`checker' + The syntax checker which reported this error, as symbol. + +`filename' + The file name the error refers to, as string. + +`line' + The line on which the error starts, as number. + +`column' (optional) + The column at which the error starts, as number. + + For compatibility with external tools and unlike Emacs + itself (e.g. in Compile Mode) Flycheck uses _1-based_ + columns: The first character on a line is column 1. + + Occasionally some tools try to proactively adapt to Emacs + and emit 0-based columns automatically. In these cases, the + columns must be adjusted for Flycheck, see + `flycheck-increment-error-columns'. + + If nil, the whole line is highlighted. + +`end-line' (optional) + The line on which the error ends. If nil, this is computed according to + `flycheck-highlighting-mode'. + +`end-column' + The column at which the error ends. If nil, this is computed according to + `flycheck-highlighting-mode'. Error intervals are right-open: the + end-column points to the first character not included in the error. For + example, 1:1 is an empty range. and in \"line-number-at-pos\", the range + 6:12 covers the word \"number\". + +`message' (optional) + The error message as a string, if any. + +`level' + The error level, as either `info', `warning' or `error'. + +`id' (optional) + An ID identifying the kind of error. + +`group' (optional) + A symbol identifying the group the error belongs to. + + Some tools will emit multiple errors that relate to the same + issue (e.g., lifetime errors in Rust). All related errors + collected by a checker should have the same `group` value, + in order to be able to present them to the user. + + See `flycheck-related-errors`." + buffer checker filename line column message level id group + ;; The fields below are at the end of the record to preserve backwards + ;; compatibility; see https://github.com/flycheck/flycheck/pull/1400 and + ;; https://lists.gnu.org/archive/html/emacs-devel/2018-07/msg00436.html + -end-line -end-column) + +;; These accessors are defined for backwards compatibility +;; FIXME: Clean up once package.el learns how to recompile dependencies. + +(defun flycheck-error-end-line (err) + "Return the end line of a Flycheck error ERR." + (condition-case nil (flycheck-error--end-line err) + (args-out-of-range nil))) + +(defun flycheck-error-end-column (err) + "Return the end column of a Flycheck error ERR." + (condition-case nil (flycheck-error--end-column err) + (args-out-of-range nil))) + +(defun flycheck-error--set-end-line (err line) + "Set the end line of a Flycheck error ERR to LINE." + (condition-case nil (setf (flycheck-error--end-line err) line) + (args-out-of-range nil))) + +(defun flycheck-error--set-end-column (err column) + "Set the end column of a Flycheck error ERR to COLUMN." + (condition-case nil (setf (flycheck-error--end-column err) column) + (args-out-of-range nil))) + +(gv-define-simple-setter flycheck-error-end-line + flycheck-error--set-end-line) +(gv-define-simple-setter flycheck-error-end-column + flycheck-error--set-end-column) + +(defmacro flycheck-error-with-buffer (err &rest forms) + "Switch to the buffer of ERR and evaluate FORMS. + +If the buffer of ERR is not live, FORMS are not evaluated." + (declare (indent 1) (debug t)) + `(when (buffer-live-p (flycheck-error-buffer ,err)) + (with-current-buffer (flycheck-error-buffer ,err) + ,@forms))) + +(defun flycheck--exact-region (err) + "Get the region of ERR, if ERR specifies a range. + +Return a cons cell `(BEG . END)'. If the input range is empty, +it is expanded to cover at least one character so that END is +always greater than BEG. If ERR doesn't specify an end-column +return nil." + (-if-let* ((line (flycheck-error-line err)) + (column (flycheck-error-column err)) + (end-line (or (flycheck-error-end-line err) line)) + (end-column (flycheck-error-end-column err))) + ;; Ignoring fields speeds up calls to `line-end-position'. + (let* ((inhibit-field-text-motion t) + (beg (flycheck-line-column-to-position line column)) + (end (flycheck-line-column-to-position end-line end-column))) + (cond + ((< beg end) (cons beg end)) + ((= end (point-max)) (cons (1- end) end)) + (t (cons end (1+ end))))))) + +(defun flycheck--line-region (pos) + "Get the line region of position POS. + +Return a cons cell `(BEG . END)' where BEG is the first +non-whitespace character on the line ERR refers to, and END the +end of the line." + (save-excursion + (goto-char pos) + (forward-line 0) + (let ((bol (point)) + (end (line-end-position))) + ;; Move to the beginning of this line's indentation, similar to + ;; `back-to-indentation' + (skip-syntax-forward " " end) + (backward-prefix-chars) + ;; If the current line is blank, highlight it in full; if it's + ;; empty, include the previous line break character(s) to have + ;; any region at all (when called with 0, `line-end-position' + ;; gives us the end of the previous line). + (cons (if (eolp) (if (= bol end) (line-end-position 0) bol) (point)) + end)))) + +(defun flycheck--column-region (pos) + "Get the column region of position POS. + +Return a cons cell `(BEG . END)' where BEG is the character +before the column, and END the actual column." + (save-excursion + (goto-char pos) + ;; (eobp): No enough lines in the buffer + (if (eobp) (cons (1- (point-max)) (point-max)) + (cons pos (1+ pos))))) + +(defun flycheck-bounds-of-thing-at-point (thing pos) + "Get the region of THING at position POS. + +THING is a understood by `thing-at-point'. + +Return a cons cell `(BEG . END)' where BEG is the beginning of +the THING at the column, and END the end of the THING." + (save-excursion + (goto-char pos) + (bounds-of-thing-at-point thing))) + +(defun flycheck--approximate-region (err mode) + "Compute the region of ERR based on MODE and ERR's line and column." + ;; Ignoring fields speeds up calls to `line-end-position'. + (let* ((inhibit-field-text-motion t) + (line (flycheck-error-line err)) + (column (flycheck-error-column err)) + (beg (flycheck-line-column-to-position line (or column 1)))) + (if (or (null column) + (eq mode 'lines)) + (flycheck--line-region beg) + (or (pcase mode + (`symbols + ;; Ensure that we're on a word or symbol. See + ;; https://github.com/flycheck/flycheck/issues/1519 + (and (< beg (point-max)) + (memq (char-syntax (char-after beg)) '(?w ?_)) + (flycheck-bounds-of-thing-at-point 'symbol beg))) + (`sexps + (flycheck-bounds-of-thing-at-point 'sexp beg))) + (flycheck--column-region beg))))) + +(defun flycheck-error-region-for-mode (err mode) + "Get the region of ERR for the highlighting MODE. + +ERR is a Flycheck error. If its position is fully specified, use +that to compute a region; otherwise, use MODE, as documented in +`flycheck-highlighting-mode'. If MODE is nil, signal an error." + (flycheck-error-with-buffer err + (save-restriction + (widen) + (or (flycheck--exact-region err) + (flycheck--approximate-region err mode))))) + +(defun flycheck-error-pos (err) + "Get the buffer position of ERR. + +ERR is a Flycheck error whose position to get. + +The error position is the error column, or the first +non-whitespace character of the error line, if ERR has no error column." + (car (flycheck-error-region-for-mode + err flycheck-highlighting-mode))) + +(defun flycheck-error-format-snippet (err &optional max-length) + "Extract the text that ERR refers to from the buffer. + +Newlines and blanks are replaced by single spaces. If ERR +doesn't include an end-position, return nil. + +MAX-LENGTH is how many characters to read from the buffer, at +most. It defaults to 20." + (flycheck-error-with-buffer err + (save-restriction + (widen) + (pcase (flycheck--exact-region err) + (`(,beg . ,end) + (truncate-string-to-width + (replace-regexp-in-string + "\\s-+" " " (buffer-substring beg (min end (point-max)))) + (or max-length 20) nil nil t)))))) + +(defun flycheck-error-format-message-and-id (err &optional include-snippet) + "Format the message and id of ERR as human-readable string. + +If INCLUDE-SNIPPET is non-nil, prepend the message with a snippet +of the text that the error applies to (such text can only be +determined if the error contains a full span, not just a +beginning position)." + (let* ((id (flycheck-error-id err)) + (fname (flycheck-error-filename err)) + (other-file-p (and fname (not (equal fname (buffer-file-name)))))) + (concat (and other-file-p (format "In %S:\n" (file-relative-name fname))) + (and include-snippet + (-when-let* ((snippet (flycheck-error-format-snippet err))) + (flycheck--format-message "`%s': " snippet))) + (or (flycheck-error-message err) + (format "Unknown %S" (flycheck-error-level err))) + (and id (format " [%s]" id))))) + +(defun flycheck-error-format-position (err) + "Format the position of ERR as a human-readable string." + (let ((line (flycheck-error-line err)) + (column (flycheck-error-column err)) + (end-line (flycheck-error-end-line err)) + (end-column (flycheck-error-end-column err))) + (if (and line column) + (if (or (null end-line) (equal line end-line)) + (if (or (null end-column) (equal column (1- end-column))) + (format "%d:%d" line column) + (format "%d:%d-%d" line column end-column)) + (format "(%d:%d)-(%d:%d)" line column end-line end-column)) + (if (or (null end-line) (equal line end-line)) + (format "%d" line) + (format "%d-%d" line end-line))))) + +(defun flycheck-error-format (err &optional with-file-name) + "Format ERR as human-readable string, optionally WITH-FILE-NAME. + +Return a string that represents the given ERR. If WITH-FILE-NAME +is given and non-nil, include the file-name as well, otherwise +omit it." + (let* ((level (symbol-name (flycheck-error-level err))) + (checker (symbol-name (flycheck-error-checker err))) + (format `(,@(when with-file-name + (list (flycheck-error-filename err) ":")) + ,(flycheck-error-format-position err) ":" + ,level ": " + ,(flycheck-error-format-message-and-id err) + " (" ,checker ")"))) + (apply #'concat format))) + +(defun flycheck-error-< (err1 err2) + "Determine whether ERR1 is less than ERR2 by location." + (let ((l1 (flycheck-error-line err1)) + (l2 (flycheck-error-line err2))) + (if (/= l1 l2) + (< l1 l2) + (let ((c1 (or (flycheck-error-column err1) 1)) + (c2 (or (flycheck-error-column err2) 1))) + (if (/= c1 c2) + (< c1 c2) + (let ((el1 (or (flycheck-error-end-line err1) l1)) + (el2 (or (flycheck-error-end-line err2) l2))) + (if (/= el1 el2) + (< el1 el2) + (let ((cl1 (or (flycheck-error-end-column err1) 1)) + (cl2 (or (flycheck-error-end-column err2) 1))) + (< cl1 cl2))))))))) + +(defun flycheck-error-level-< (err1 err2) + "Determine whether ERR1 is less than ERR2 by error level. + +Like `flycheck-error-<', but compares by error level severity +first. Levels of the same severity are compared by name." + (let* ((level1 (flycheck-error-level err1)) + (level2 (flycheck-error-level err2)) + (severity1 (flycheck-error-level-severity level1)) + (severity2 (flycheck-error-level-severity level2))) + (cond + ((= severity1 severity2) + (if (string= level1 level2) + (flycheck-error-< err1 err2) + (string< level1 level2))) + (t (< severity1 severity2))))) + +(defun flycheck-assert-error-list-p (errors) + "Assert that all items in ERRORS are of `flycheck-error' type. + +Signal an error if any item in ERRORS is not a `flycheck-error' +object, as by `flycheck-error-p'. Otherwise return ERRORS +again." + (unless (listp errors) + (signal 'wrong-type-argument (list 'listp errors))) + (dolist (err errors) + (unless (flycheck-error-p err) + (signal 'wrong-type-argument (list 'flycheck-error-p err)))) + errors) + + +;;; Errors in the current buffer +(defvar-local flycheck-current-errors nil + "A list of all errors and warnings in the current buffer.") + +(defun flycheck-report-current-errors (errors) + "Report ERRORS in the current buffer. + +Add ERRORS to `flycheck-current-errors' and process each error +with `flycheck-process-error-functions'." + (setq flycheck-current-errors (append errors flycheck-current-errors)) + (overlay-recenter (point-max)) + ;; We can't use `seq-sort-by' because it's not in Emacs 25's built-in `seq', + ;; and installing an updated version doesn't help (this is a package.el bug; + ;; see https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg01974.html). + (seq-do (lambda (err) + (run-hook-with-args-until-success 'flycheck-process-error-functions + err)) + (seq-sort (lambda (e1 e2) + (< (flycheck-error-line e1) (flycheck-error-line e2))) + errors))) + +(defun flycheck-clear-errors () + "Remove all error information from the current buffer." + (setq flycheck-current-errors nil) + (flycheck-report-status 'not-checked)) + +(defun flycheck-fill-and-expand-error-file-names (errors directory) + "Fill and expand file names in ERRORS relative to DIRECTORY. + +Expand all file names of ERRORS against DIRECTORY. If the file +name of an error is nil fill in the result of function +`buffer-file-name' in the current buffer. + +Return ERRORS, modified in-place." + (seq-do (lambda (err) + (setf (flycheck-error-filename err) + (-if-let (filename (flycheck-error-filename err)) + (expand-file-name filename directory) + (buffer-file-name)))) + errors) + errors) + +(defun flycheck-relevant-error-other-file-p (err) + "Determine whether ERR is a relevant error for another file." + (let ((file-name (flycheck-error-filename err))) + (and file-name + flycheck-relevant-error-other-file-show + (or (null buffer-file-name) + (not (flycheck-same-files-p buffer-file-name file-name))) + (<= (flycheck-error-level-severity + flycheck-relevant-error-other-file-minimum-level) + (flycheck-error-level-severity (flycheck-error-level err)))))) + +(defun flycheck-relevant-error-p (err) + "Determine whether ERR is relevant for the current buffer. + +Return t if ERR may be shown for the current buffer, or nil +otherwise." + (flycheck-error-with-buffer err + (let ((file-name (flycheck-error-filename err)) + (message (flycheck-error-message err))) + (and + (or + ;; Neither the error nor buffer have a file name + (and (not file-name) (not buffer-file-name)) + ;; Both have files, and they match + (and buffer-file-name file-name + (flycheck-same-files-p file-name buffer-file-name)) + ;; This is a significant error from another file + (flycheck-relevant-error-other-file-p err)) + message + (not (string-empty-p message)) + ;; Errors without line numbers are discarded. If a linter + ;; reports relevant errors without line numbers, use + ;; `flycheck-fill-empty-line-numbers' as the checker's + ;; `:error-filter' to set them to line 0. + (flycheck-error-line err))))) + +(defun flycheck-relevant-errors (errors) + "Filter the relevant errors from ERRORS. + +Return a list of all errors that are relevant for their +corresponding buffer." + (seq-filter #'flycheck-relevant-error-p errors)) + +(defun flycheck-related-errors (err &optional error-set) + "Get all the errors that are in the same group as ERR. + +Return a list of all errors (from ERROR-SET) that have the same +`flycheck-error-group' as ERR, including ERR itself. + +If ERROR-SET is nil, `flycheck-current-errors' is used instead." + (let ((group (flycheck-error-group err)) + (checker (flycheck-error-checker err))) + (if group + (seq-filter (lambda (e) + (and (eq (flycheck-error-checker e) checker) + (eq (flycheck-error-group e) group))) + (or error-set flycheck-current-errors)) + (list err)))) + + +;;; Status reporting for the current buffer +(defvar-local flycheck-last-status-change 'not-checked + "The last status change in the current buffer.") + +(defun flycheck-report-failed-syntax-check (&optional status) + "Report a failed Flycheck syntax check with STATUS. + +STATUS is a status symbol for `flycheck-report-status', +defaulting to `errored'. + +Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and +report an error STATUS." + (flycheck-clear) + (setq flycheck-current-syntax-check nil) + (run-hooks 'flycheck-syntax-check-failed-hook) + (flycheck-report-status (or status 'errored))) + +(defun flycheck-report-status (status) + "Report Flycheck STATUS. + +STATUS is one of the following symbols: + +`not-checked' + The current buffer was not checked. + +`no-checker' + Automatic syntax checker selection did not find a suitable + syntax checker. + +`running' + A syntax check is now running in the current buffer. + +`errored' + The current syntax check has errored. + +`finished' + The current syntax check was finished normally. + +`interrupted' + The current syntax check was interrupted. + +`suspicious' + The last syntax check had a suspicious result. + +Set `flycheck-last-status-change' and call +`flycheck-status-changed-functions' with STATUS. Afterwards +refresh the mode line." + (setq flycheck-last-status-change status) + (run-hook-with-args 'flycheck-status-changed-functions status) + (force-mode-line-update)) + +(defun flycheck-mode-line-status-text (&optional status) + "Get a text describing STATUS for use in the mode line. + +STATUS defaults to `flycheck-last-status-change' if omitted or +nil." + (let ((text (pcase (or status flycheck-last-status-change) + (`not-checked "") + (`no-checker "-") + (`running "*") + (`errored "!") + (`finished + (let-alist (flycheck-count-errors flycheck-current-errors) + (if (or .error .warning) + (format ":%s|%s" (or .error 0) (or .warning 0)) + ""))) + (`interrupted ".") + (`suspicious "?")))) + (concat " " flycheck-mode-line-prefix text))) + + +;;; Error levels +(defun flycheck-make-margin-spec (margin-str face) + "Make a display spec to indicate errors in the margins. + +Returns MARGIN-STR with FACE applied." + (propertize margin-str 'face `(,face default))) + +(defconst flycheck-default-margin-str "»" + "String used to indicate errors in the margins.") + +(defconst flycheck-default-margin-continuation-str "⋮" + "String used to indicate continuation lines in the margins.") + +;;;###autoload +(defun flycheck-define-error-level (level &rest properties) + "Define a new error LEVEL with PROPERTIES. + +The following PROPERTIES constitute an error level: + +`:severity SEVERITY' + A number denoting the severity of this level. The higher + the number, the more severe is this level compared to other + levels. Defaults to 0; info is -10, warning is 10, and + error is 100. + + The severity is used by `flycheck-error-level-<' to + determine the ordering of errors according to their levels. + +`:compilation-level LEVEL' + + A number indicating the broad class of messages that errors + at this level belong to: one of 0 (info), 1 (warning), or + 2 or nil (error). Defaults to nil. + + This is used by `flycheck-checker-pattern-to-error-regexp' + to map error levels into `compilation-mode''s hierarchy and + to get proper highlighting of errors in `compilation-mode'. + +`:overlay-category CATEGORY' + A symbol denoting the overlay category to use for error + highlight overlays for this level. See Info + node `(elisp)Overlay Properties' for more information about + overlay categories. + + A category for an error level overlay should at least define + the `face' property, for error highlighting. Another useful + property for error level categories is `priority', to + influence the stacking of multiple error level overlays. + +`:fringe-bitmap BITMAPS' + A fringe bitmap symbol denoting the bitmap to use for fringe + indicators for this level, or a cons of two bitmaps (one for + narrow fringes and one for wide fringes). See Info node + `(elisp)Fringe Bitmaps' for more information about fringe + bitmaps, including a list of built-in fringe bitmaps. + +`:fringe-face FACE' + A face symbol denoting the face to use for fringe indicators + for this level. + +`:margin-spec SPEC' + A display specification indicating what to display in the + margin when `flycheck-indication-mode' is `left-margin' or + `right-margin'. See Info node `(elisp)Displaying in the + Margins'. If omitted, Flycheck generates an image spec from + the fringe bitmap. + +`:error-list-face FACE' + A face symbol denoting the face to use for messages of this + level in the error list. See `flycheck-list-errors'." + (declare (indent 1)) + (setf (get level 'flycheck-error-level) t) + (setf (get level 'flycheck-error-severity) + (or (plist-get properties :severity) 0)) + (setf (get level 'flycheck-compilation-level) + (plist-get properties :compilation-level)) + (setf (get level 'flycheck-overlay-category) + (plist-get properties :overlay-category)) + (setf (get level 'flycheck-fringe-bitmaps) + (let ((bitmap (plist-get properties :fringe-bitmap))) + (if (consp bitmap) bitmap (cons bitmap bitmap)))) + ;; Kept for compatibility + (setf (get level 'flycheck-fringe-bitmap-double-arrow) + (car (get level 'flycheck-fringe-bitmaps))) + (setf (get level 'flycheck-fringe-face) + (plist-get properties :fringe-face)) + (setf (get level 'flycheck-margin-spec) + (or (plist-get properties :margin-spec) + (flycheck-make-margin-spec + flycheck-default-margin-str + (or (get level 'flycheck-fringe-face) 'default)))) + (setf (get level 'flycheck-margin-continuation) + (flycheck-make-margin-spec + flycheck-default-margin-continuation-str + (or (get level 'flycheck-fringe-face) 'default))) + (setf (get level 'flycheck-error-list-face) + (plist-get properties :error-list-face))) + +(defun flycheck-error-level-p (level) + "Determine whether LEVEL is a Flycheck error level." + (get level 'flycheck-error-level)) + +(defun flycheck-error-level-severity (level) + "Get the numeric severity of LEVEL." + (or (get level 'flycheck-error-severity) 0)) + +(defun flycheck-error-level-compilation-level (level) + "Get the compilation level for LEVEL." + (get level 'flycheck-compilation-level)) + +(defun flycheck-error-level-overlay-category (level) + "Get the overlay category for LEVEL." + (get level 'flycheck-overlay-category)) + +(defun flycheck-error-level-margin-spec (level) + "Get the margin spec for LEVEL." + (get level 'flycheck-margin-spec)) + +(defun flycheck-error-level-margin-continuation-spec (level) + "Get the margin continuation spec for LEVEL." + (get level 'flycheck-margin-continuation)) + +(defun flycheck-error-level-fringe-bitmap (level &optional hi-res) + "Get the fringe bitmap for LEVEL. + +Optional argument HI-RES non-nil means that the returned bitmap +will be the high resolution version." + (let ((bitmaps (get level 'flycheck-fringe-bitmaps))) + (if hi-res (cdr bitmaps) (car bitmaps)))) + +(defun flycheck-error-level-fringe-face (level) + "Get the fringe face for LEVEL." + (get level 'flycheck-fringe-face)) + +(defun flycheck-error-level-error-list-face (level) + "Get the error list face for LEVEL." + (get level 'flycheck-error-list-face)) + +(defun flycheck-error-level-make-indicator (level side &optional continuation) + "Create the fringe or margin icon for LEVEL at SIDE. + +Return a propertized string that shows an indicator according +to LEVEL and the given fringe or margin SIDE. + +LEVEL is a Flycheck error level defined with +`flycheck-define-error-level', and SIDE is either `left-fringe', +`right-fringe', `left-margin', or `right-margin'. + +CONTINUATION indicates which fringe bitmap or margin spec to use: +either the `:fringe-bitmap' and `:margin-spec' properties of +LEVEL when CONTINUATION is nil or omitted, or bitmaps and specs +indicating an error spanning more than one line. + +Return a propertized string representing the fringe icon, +intended for use as `before-string' of an overlay to actually +show the indicator." + (propertize + "!" 'display + (pcase side + ((or `left-fringe `right-fringe) + (list side + (if continuation 'flycheck-fringe-bitmap-continuation + (let* ((fringe-width + (pcase side + (`left-fringe (car (window-fringes))) + (`right-fringe (cadr (window-fringes))))) + (high-res (>= fringe-width 16))) + (flycheck-error-level-fringe-bitmap level high-res))) + (flycheck-error-level-fringe-face level))) + ((or `left-margin `right-margin) + `((margin ,side) + ,(or (if continuation + (flycheck-error-level-margin-continuation-spec level) + (flycheck-error-level-margin-spec level)) + ""))) + (_ (error "Invalid fringe side: %S" side))))) + +(define-obsolete-function-alias + 'flycheck-error-level-make-fringe-icon + 'flycheck-error-level-make-indicator + "33") + + +;;; Built-in error levels +(defconst flycheck-fringe-bitmap-double-arrow + [#b11011000 + #b01101100 + #b00110110 + #b00011011 + #b00110110 + #b01101100 + #b11011000] + "Bitmaps used to indicate errors in the fringes.") + +(defconst flycheck-fringe-bitmap-double-arrow-hi-res + [#b1111001111000000 + #b0111100111100000 + #b0011110011110000 + #b0001111001111000 + #b0000111100111100 + #b0000011110011110 + #b0000011110011110 + #b0000111100111100 + #b0001111001111000 + #b0011110011110000 + #b0111100111100000 + #b1111001111000000] + "High-resolution bitmap used to indicate errors in the fringes.") + +(defconst flycheck-fringe-bitmap-continuation + [#b1000000010000000 + #b0010000000100000 + #b0000100000001000 + #b0000001000000010] + "Bitmap used to indicate continuation lines in the fringes.") + +(when (fboundp 'define-fringe-bitmap) ;; #ifdef HAVE_WINDOW_SYSTEM + (define-fringe-bitmap + 'flycheck-fringe-bitmap-double-arrow + flycheck-fringe-bitmap-double-arrow) + (define-fringe-bitmap + 'flycheck-fringe-bitmap-double-arrow-hi-res + flycheck-fringe-bitmap-double-arrow-hi-res + nil 16) + (define-fringe-bitmap + 'flycheck-fringe-bitmap-continuation + flycheck-fringe-bitmap-continuation + nil 16 '(top repeat))) + +(defun flycheck-redefine-standard-error-levels + (&optional margin-str fringe-bitmap) + "Redefine Flycheck's standard error levels. + +This is useful to change the character drawn in the +margins (MARGIN-STR, a string) or the bitmap drawn in the +fringes (FRINGE-BITMAP, a fringe bitmap symbol or a cons of such +symbols, as in `flycheck-define-error-level')." + (unless margin-str + (setq margin-str flycheck-default-margin-str)) + + (unless fringe-bitmap + (setq fringe-bitmap + (cons 'flycheck-fringe-bitmap-double-arrow + 'flycheck-fringe-bitmap-double-arrow-hi-res))) + + (setf (get 'flycheck-error-overlay 'face) 'flycheck-error) + (setf (get 'flycheck-error-overlay 'priority) 110) + + (flycheck-define-error-level 'error + :severity 100 + :compilation-level 2 + :overlay-category 'flycheck-error-overlay + :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-error) + :fringe-bitmap fringe-bitmap + :fringe-face 'flycheck-fringe-error + :error-list-face 'flycheck-error-list-error) + + (setf (get 'flycheck-warning-overlay 'face) 'flycheck-warning) + (setf (get 'flycheck-warning-overlay 'priority) 100) + + (flycheck-define-error-level 'warning + :severity 10 + :compilation-level 1 + :overlay-category 'flycheck-warning-overlay + :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-warning) + :fringe-bitmap fringe-bitmap + :fringe-face 'flycheck-fringe-warning + :error-list-face 'flycheck-error-list-warning) + + (setf (get 'flycheck-info-overlay 'face) 'flycheck-info) + (setf (get 'flycheck-info-overlay 'priority) 90) + + (flycheck-define-error-level 'info + :severity -10 + :compilation-level 0 + :overlay-category 'flycheck-info-overlay + :margin-spec (flycheck-make-margin-spec margin-str 'flycheck-fringe-info) + :fringe-bitmap fringe-bitmap + :fringe-face 'flycheck-fringe-info + :error-list-face 'flycheck-error-list-info)) + +(flycheck-redefine-standard-error-levels) + + +;;; Error filtering +(defun flycheck-filter-errors (errors checker) + "Filter ERRORS from CHECKER. + +Apply the error filter of CHECKER to ERRORs and return the +result. If CHECKER has no error filter, fall back to +`flycheck-sanitize-errors'." + (let ((filter (or (flycheck-checker-get checker 'error-filter) + #'flycheck-sanitize-errors))) + (funcall filter errors))) + +(defun flycheck-sanitize-errors (errors) + "Sanitize ERRORS. + +Sanitize ERRORS by trimming leading and trailing whitespace in +all error messages, and by replacing 0 columns and empty error +messages with nil. + +Returns sanitized ERRORS." + (dolist (err errors) + (flycheck-error-with-buffer err + (let ((message (flycheck-error-message err)) + (id (flycheck-error-id err))) + (when message + (setq message (string-trim message)) + (setf (flycheck-error-message err) + (if (string-empty-p message) nil message))) + (when (and id (string-empty-p id)) + (setf (flycheck-error-id err) nil)) + (when (eq (flycheck-error-column err) 0) + (setf (flycheck-error-column err) nil)) + (when (eq (flycheck-error-end-column err) 0) + (setf (flycheck-error-end-column err) nil))))) + errors) + +(defun flycheck-remove-error-file-names (file-name errors) + "Remove matching FILE-NAME from ERRORS. + +Use as `:error-filter' for syntax checkers that output faulty +filenames. Flycheck will later fill in the buffer file name. + +Return ERRORS." + (seq-do (lambda (err) + (when (and (flycheck-error-filename err) + (string= (flycheck-error-filename err) file-name)) + (setf (flycheck-error-filename err) nil))) + errors) + errors) + +(defun flycheck-increment-error-columns (errors &optional offset) + "Increment all columns of ERRORS by OFFSET (default: 1). + + Use this as `:error-filter' if a syntax checker outputs 0-based + columns." + (setq offset (or offset 1)) ;; Emacs bug #31715 + (seq-do (lambda (err) + (when (flycheck-error-column err) + (cl-incf (flycheck-error-column err) offset)) + (when (flycheck-error-end-column err) + (cl-incf (flycheck-error-end-column err) offset))) + errors) + errors) + +(defun flycheck-collapse-error-message-whitespace (errors) + "Collapse whitespace in all messages of ERRORS. + +Return ERRORS." + (dolist (err errors) + (-when-let (message (flycheck-error-message err)) + (setf (flycheck-error-message err) + (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r"))) + " " message 'fixed-case 'literal)))) + errors) + +(defun flycheck-dedent-error-messages (errors) + "Dedent all messages of ERRORS. + +For each error in ERRORS, determine the indentation offset from +the leading whitespace of the first line, and dedent all further +lines accordingly. + +Return ERRORS, with in-place modifications." + (dolist (err errors) + (-when-let (message (flycheck-error-message err)) + (with-temp-buffer + (insert message) + ;; Determine the indentation offset + (goto-char (point-min)) + (back-to-indentation) + (let* ((indent-offset (- (point) (point-min)))) + ;; Now iterate over all lines and dedent each according to + ;; `indent-offset' + (while (not (eobp)) + (back-to-indentation) + ;; If the current line starts with sufficient whitespace, delete the + ;; indentation offset. Otherwise keep the line intact, as we might + ;; loose valuable information + (when (>= (- (point) (line-beginning-position)) indent-offset) + (delete-char (- indent-offset))) + (forward-line 1))) + (delete-trailing-whitespace (point-min) (point-max)) + (setf (flycheck-error-message err) + (buffer-substring-no-properties (point-min) (point-max)))))) + errors) + +(defun flycheck-fold-include-levels (errors sentinel-message) + "Fold levels of ERRORS from included files. + +ERRORS is a list of `flycheck-error' objects. SENTINEL-MESSAGE +is a regular expression matched against the error message to +determine whether the error denotes errors from an included +file. Alternatively, it is a function that is given an error and +shall return non-nil, if the error denotes errors from an +included file." + (unless (or (stringp sentinel-message) (functionp sentinel-message)) + (error "Sentinel must be string or function: %S" sentinel-message)) + (let ((sentinel (if (functionp sentinel-message) + sentinel-message + (lambda (err) + (string-match-p sentinel-message + (flycheck-error-message err))))) + (remaining-errors errors)) + (while remaining-errors + (let* ((current-error (pop remaining-errors))) + (when (funcall sentinel current-error) + ;; We found an error denoting errors in the included file: + ;; 1. process all subsequent errors until faulty include file is found + ;; 2. process again all subsequent errors until an error has the + ;; current file name again + ;; 3. find the most severe error level + (let ((current-filename (flycheck-error-filename current-error)) + (current-level nil) + (faulty-include-filename nil) + (filename nil) + (done (null remaining-errors))) + + (while (not done) + (setq filename (flycheck-error-filename (car remaining-errors))) + (unless faulty-include-filename + (unless (string= filename current-filename) + (setq faulty-include-filename filename))) + + (let* ((error-in-include (pop remaining-errors)) + (in-include-level (flycheck-error-level error-in-include))) + (unless (funcall sentinel error-in-include) + ;; Ignore nested "included file" errors, we are only + ;; interested in real errors because these define our level + (when (or (not current-level) + (> (flycheck-error-level-severity in-include-level) + (flycheck-error-level-severity current-level))) + (setq current-level in-include-level)))) + + (setq done (or (null remaining-errors) + (and faulty-include-filename + (string= filename current-filename))))) + + (setf (flycheck-error-level current-error) current-level + (flycheck-error-message current-error) + (format "In include %s" faulty-include-filename)))))) + errors)) + +(defun flycheck-dequalify-error-ids (errors) + "De-qualify error ids in ERRORS. + +Remove all qualifications from error ids in ERRORS, by stripping +all leading dotted components from error IDs. For instance, if +the error ID is com.foo.E100, replace it with E100. + +This error filter is mainly useful to simplify error IDs obtained +from parsing Checkstyle XML, which frequently has very verbose +IDs, that include the name of the tool." + (seq-do (lambda (err) + (let ((id (flycheck-error-id err))) + (when id + (setf (flycheck-error-id err) + (replace-regexp-in-string + (rx string-start + (group + (optional (zero-or-more not-newline) ".")) + (one-or-more (not (any "."))) + string-end) + "" id 'fixedcase 'literal 1))))) + errors) + errors) + +(defun flycheck-remove-error-ids (errors) + "Remove all error ids from ERRORS." + (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors) + errors) + +(defun flycheck-fill-empty-line-numbers (errors) + "Set ERRORS without lines to line 0. + +Use as `:error-filter' for syntax checkers that output errors +without line numbers. + +Return ERRORS." + (seq-do (lambda (err) + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 0))) + errors) + errors) + + +;;; Error analysis +(defun flycheck-count-errors (errors) + "Count the number of ERRORS, grouped by level. + +Return an alist, where each ITEM is a cons cell whose `car' is an +error level, and whose `cdr' is the number of errors of that +level." + (let (counts-by-level) + (dolist (err errors) + (let* ((level (flycheck-error-level err)) + (item (assq level counts-by-level))) + (if item + (cl-incf (cdr item)) + (push (cons level 1) counts-by-level)))) + counts-by-level)) + +(defun flycheck-has-max-errors-p (errors level) + "Check if there is no error in ERRORS more severe than LEVEL." + (let ((severity (flycheck-error-level-severity level))) + (seq-every-p (lambda (e) (<= (flycheck-error-level-severity + (flycheck-error-level e)) + severity)) + errors))) + +(defun flycheck-has-max-current-errors-p (level) + "Check if there is no current error more severe than LEVEL." + (flycheck-has-max-errors-p flycheck-current-errors level)) + +(defun flycheck-has-errors-p (errors level) + "Determine if there are any ERRORS with LEVEL." + (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors)) + +(defun flycheck-has-current-errors-p (&optional level) + "Determine if the current buffer has errors with LEVEL. + +If LEVEL is omitted if the current buffer has any errors at all." + (if level + (flycheck-has-errors-p flycheck-current-errors level) + (and flycheck-current-errors t))) + + +;;; Error overlays in the current buffer +(defvar-local flycheck--last-overlay-index 0 + "Last index given to a Flycheck overlay. + +These indices are used to preserve error order (Emacs doesn't +preserve overlay order when calling `overlays-at').") + +(defun flycheck--next-overlay-index () + "Compute the index to assign to a new Flycheck overlay." + (cl-incf flycheck--last-overlay-index)) + +(defun flycheck--highlighting-style (err) + "Determine the highlighting style to apply to ERR. + +Styles are documented in `flycheck-highlighting-style'; this +functions resolves `conditional' style specifications." + (let* ((style flycheck-highlighting-style) + (first-line (flycheck-error-line err)) + (end-line (or (flycheck-error-end-line err) first-line)) + (nlines (- end-line first-line))) + (while (eq (car-safe style) 'conditional) + (pcase-let ((`(,threshold ,s1 ,s2) (cdr style))) + (setq style (if (< nlines threshold) s1 s2)))) + (pcase style + (`(delimiters ,before ,after) + (when (characterp before) + (setq before (flycheck--make-highlighting-delimiter before))) + (when (characterp after) + (setq after (flycheck--make-highlighting-delimiter after))) + (setq style `(delimiters ,before ,after)))) + style)) + +(defun flycheck--setup-highlighting (err overlay) + "Apply properties to OVERLAY to highlight ERR." + (let ((level (flycheck-error-level err))) + (unless flycheck-highlighting-mode + ;; Erase the highlighting from the overlay if requested by the user + (setf (overlay-get overlay 'face) nil)) + (when flycheck-indication-mode + (setf (overlay-get overlay 'before-string) + (flycheck-error-level-make-indicator + level flycheck-indication-mode)) + (setf (overlay-get overlay 'line-prefix) + (flycheck-error-level-make-indicator + level flycheck-indication-mode t))) + (pcase (flycheck--highlighting-style err) + ((or `nil (guard (null flycheck-highlighting-mode))) + ;; Erase the highlighting + (setf (overlay-get overlay 'face) nil)) + (`level-face) + (`(delimiters ,before ,after) + ;; Replace the highlighting with delimiters + (let* ((fringe-face (flycheck-error-level-fringe-face level)) + (delim-face `(flycheck-error-delimiter ,fringe-face))) + (setf (overlay-get overlay 'face) 'flycheck-delimited-error) + (setf (overlay-get overlay 'before-string) + (concat (propertize before 'face delim-face) + (or (overlay-get overlay 'before-string) ""))) + (setf (overlay-get overlay 'after-string) + (propertize after 'face delim-face)))) + (other (error "Unsupported highlighting style: %S" other))))) + +(defun flycheck-add-overlay (err) + "Add overlay for ERR. + +Return the created overlay." + ;; We must have a proper error region for the sake of fringe indication, + ;; error display and error navigation, even if the highlighting is disabled. + ;; We erase the highlighting later on in this case + (pcase-let* ((`(,beg . ,end) + (if (flycheck-relevant-error-other-file-p err) + ;; Display overlays for other-file errors on the first line + (cons (point-min) + (save-excursion (goto-char (point-min)) + (point-at-eol))) + (flycheck-error-region-for-mode + err (or flycheck-highlighting-mode 'lines)))) + (overlay (make-overlay beg end)) + (level (flycheck-error-level err)) + (category (flycheck-error-level-overlay-category level)) + (index (flycheck--next-overlay-index))) + (unless (flycheck-error-level-p level) + (error "Undefined error level: %S" level)) + (setf (overlay-get overlay 'flycheck-error-index) index) + (setf (overlay-get overlay 'flycheck-overlay) t) + (setf (overlay-get overlay 'flycheck-error) err) + (setf (overlay-get overlay 'category) category) + (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo) + (flycheck--setup-highlighting err overlay) + overlay)) + +(defun flycheck-help-echo (_window object pos) + "Construct a tooltip message. + +Most of the actual work is done by calling +`flycheck-help-echo-function' with the appropriate list of +errors. Arguments WINDOW, OBJECT and POS are as described in +info node `(elisp)Special properties', as this function is +intended to be used as the 'help-echo property of flycheck error +overlays." + (-when-let (buf (cond ((bufferp object) object) + ((overlayp object) (overlay-buffer object)))) + (with-current-buffer buf + (-when-let* ((fn flycheck-help-echo-function) + (errs (flycheck-overlay-errors-at pos))) + (propertize (funcall fn errs) 'help-echo-inhibit-substitution t))))) + +(defun flycheck-help-echo-all-error-messages (errs) + "Concatenate error messages and ids from ERRS." + (pcase (delq nil errs) ;; FIXME why would errors be nil here? + (`(,err) ;; A single error + (flycheck-error-format-message-and-id err)) + (_ ;; Zero or multiple errors + (mapconcat + (lambda (err) + (flycheck-error-format-message-and-id err 'include-snippet)) + errs "\n")))) + +(defun flycheck-filter-overlays (overlays) + "Get all Flycheck overlays from OVERLAYS, in original order." + ;; The order of errors returned from overlays is not stable, so we sort + ;; them again using the internal index to guarantee errors are always + ;; displayed in the same order. + (seq-sort + ;; We can't use `seq-sort-by' here; see above + (lambda (o1 o2) (< (overlay-get o1 'flycheck-error-index) + (overlay-get o2 'flycheck-error-index))) + (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays))) + +(defun flycheck-overlays-at (pos) + "Get all Flycheck overlays at POS." + (flycheck-filter-overlays (overlays-at pos))) + +(defun flycheck-overlays-in (beg end) + "Get all Flycheck overlays between BEG and END." + (flycheck-filter-overlays (overlays-in beg end))) + +(defun flycheck-overlay-errors-at (pos) + "Return a list of all flycheck errors overlaid at POS." + (seq-map (lambda (o) (overlay-get o 'flycheck-error)) + (flycheck-overlays-at pos))) + +(defun flycheck-overlay-errors-in (beg end) + "Return a list of all flycheck errors overlaid between BEG and END." + (seq-map (lambda (o) (overlay-get o 'flycheck-error)) + (flycheck-overlays-in beg end))) + +(defvar-local flycheck-overlays-to-delete nil + "Overlays mark for deletion after all syntax checks completed.") +(put 'flycheck-overlays-to-delete 'permanent-local t) + +(defun flycheck-delete-all-overlays () + "Remove all flycheck overlays in the current buffer." + (overlay-recenter (point-max)) + (flycheck-delete-marked-overlays) + (setq flycheck--last-overlay-index 0) + (save-restriction + (widen) + (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max))))) + +(defun flycheck-mark-all-overlays-for-deletion () + "Mark all current overlays for deletion." + (setq flycheck-overlays-to-delete + (append (flycheck-overlays-in (point-min) (point-max)) + flycheck-overlays-to-delete))) + +(defun flycheck-delete-marked-overlays () + "Delete all overlays marked for deletion." + (overlay-recenter (point-max)) + (seq-do #'delete-overlay flycheck-overlays-to-delete) + (setq flycheck-overlays-to-delete nil)) + + +;;; Error navigation in the current buffer +(defun flycheck-error-level-interesting-at-pos-p (pos) + "Check if error severity at POS passes `flycheck-error-level-interesting-p'." + (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error))) + +(defun flycheck-error-level-interesting-p (err) + "Check if ERR severity is >= `flycheck-navigation-minimum-level'. + +ERR is also interesting (the function returns true) if there are +no errors as or more severe than `flycheck-navigation-minimum-level'." + (when (flycheck-error-p err) + (-if-let (min-level flycheck-navigation-minimum-level) + (or (<= (flycheck-error-level-severity min-level) + (flycheck-error-level-severity (flycheck-error-level err))) + (not (flycheck-has-current-errors-p min-level))) + t))) + +(defun flycheck-next-error-pos (n &optional reset) + "Get the position of the N-th next error. + +With negative N, get the position of the (-N)-th previous error +instead. With non-nil RESET, search from `point-min', otherwise +search from the current point. + +Return the position of the next or previous error, or nil if +there is none. If N is zero, return `point', or `point-min' if +RESET is non-nil." + (let ((n (or n 1)) + (pos (if reset (point-min) (point)))) + (if (>= n 0) + ;; Search forwards + (while (and pos (> n 0)) + (setq n (1- n)) + (when (get-char-property pos 'flycheck-error) + ;; Move beyond from the current error if any + (setq pos (next-single-char-property-change pos 'flycheck-error))) + (while (not (or (= pos (point-max)) + (flycheck-error-level-interesting-at-pos-p pos))) + ;; Scan for the next error + (setq pos (next-single-char-property-change pos 'flycheck-error))) + (when (and (= pos (point-max)) + (not (flycheck-error-level-interesting-at-pos-p pos))) + ;; If we reached the end of the buffer, but no error, we didn't find + ;; any + (setq pos nil))) + ;; Search backwards + (while (and pos (< n 0)) + (setq n (1+ n)) + ;; Loop until we find an error. We need to check the position *before* + ;; the current one, because `previous-single-char-property-change' + ;; always moves to the position *of* the change. + (while (not (or (= pos (point-min)) + (flycheck-error-level-interesting-at-pos-p (1- pos)))) + (setq pos (previous-single-char-property-change pos 'flycheck-error))) + (when (and (= pos (point-min)) + (not (flycheck-error-level-interesting-at-pos-p pos))) + ;; We didn't find any error. + (setq pos nil)) + (when pos + ;; We found an error, so move to its beginning + (setq pos (previous-single-char-property-change pos + 'flycheck-error))))) + pos)) + +(defun flycheck-next-error-function (n reset) + "Visit the N-th error from the current point. + +N is the number of errors to advance by, where a negative N +advances backwards. With non-nil RESET, advance from the +beginning of the buffer, otherwise advance from the current +position. + +Intended for use with `next-error-function'." + (-if-let* ((pos (flycheck-next-error-pos n reset)) + (err (get-char-property pos 'flycheck-error))) + (flycheck-jump-to-error err) + (user-error "No more Flycheck errors"))) + +(defun flycheck-next-error (&optional n reset) + "Visit the N-th error from the current point. + +N is the number of errors to advance by, where a negative N +advances backwards. With non-nil RESET, advance from the +beginning of the buffer, otherwise advance from the current +position." + (interactive "P") + (when (consp n) + ;; Universal prefix argument means reset + (setq reset t n nil)) + (flycheck-next-error-function n reset) + (flycheck-display-error-at-point)) + +(defun flycheck-previous-error (&optional n) + "Visit the N-th previous error. + +If given, N specifies the number of errors to move backwards by. +If N is negative, move forwards instead." + (interactive "P") + (flycheck-next-error (- (or n 1)))) + +(defun flycheck-first-error (&optional n) + "Visit the N-th error from beginning of the buffer. + +If given, N specifies the number of errors to move forward from +the beginning of the buffer." + (interactive "P") + (flycheck-next-error n 'reset)) + + +;;; Listing errors in buffers +(defconst flycheck-error-list-buffer "*Flycheck errors*" + "The name of the buffer to show error lists.") + +(defmacro flycheck-error-list-with-buffer (&rest body) + "Evaluate BODY in flycheck-error-list-buffer, if it exists." + (declare (indent 0) (debug t)) + `(when (get-buffer flycheck-error-list-buffer) + (with-current-buffer flycheck-error-list-buffer + ,@body))) + +(defvar flycheck-error-list-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "f") #'flycheck-error-list-set-filter) + (define-key map (kbd "F") #'flycheck-error-list-reset-filter) + (define-key map (kbd "n") #'flycheck-error-list-next-error) + (define-key map (kbd "p") #'flycheck-error-list-previous-error) + (define-key map (kbd "g") #'flycheck-error-list-check-source) + (define-key map (kbd "e") #'flycheck-error-list-explain-error) + (define-key map (kbd "RET") #'flycheck-error-list-goto-error) + map) + "The keymap of `flycheck-error-list-mode'.") + +(defun flycheck-error-list-make-last-column (message checker) + "Compute contents of the last error list cell. + +MESSAGE and CHECKER are displayed in a single column to allow the +message to stretch arbitrarily far." + (let ((checker-name (propertize (symbol-name checker) + 'face 'flycheck-error-list-checker-name)) + (message (propertize message + 'face 'flycheck-error-list-error-message))) + (format "%s (%s)" message checker-name))) + +(defconst flycheck-error-list-format + `[("File" 6) + ("Line" 5 flycheck-error-list-entry-< :right-align t) + ("Col" 3 nil :right-align t) + ("Level" 8 flycheck-error-list-entry-level-<) + ("ID" 6 t) + (,(flycheck-error-list-make-last-column "Message" 'Checker) 0 t)] + "Table format for the error list.") + +(defconst flycheck-error-list-padding 1 + "Padding used in error list.") + +(defconst flycheck--error-list-msg-offset + (seq-reduce + (lambda (offset fmt) + (pcase-let* ((`(,_ ,width ,_ . ,props) fmt) + (padding (or (plist-get props :pad-right) 1))) + (+ offset width padding))) + (seq-subseq flycheck-error-list-format 0 -1) + flycheck-error-list-padding) + "Amount of space to use in `flycheck-flush-multiline-message'.") + +(define-derived-mode flycheck-error-list-mode tabulated-list-mode + "Flycheck errors" + "Major mode for listing Flycheck errors. + +\\{flycheck-error-list-mode-map}" + (setq tabulated-list-format flycheck-error-list-format + ;; Sort by location initially + tabulated-list-sort-key (cons "Line" nil) + tabulated-list-padding flycheck-error-list-padding + tabulated-list-entries #'flycheck-error-list-entries + ;; `revert-buffer' updates the mode line for us, so all we need to do is + ;; set the corresponding mode line construct. + mode-line-buffer-identification flycheck-error-list-mode-line) + ;; Guard `truncate-string-ellipsis' for Emacs 24. + ;; TODO: Remove when dropping Emacs 24 compatibility + (when (boundp 'truncate-string-ellipsis) + ;; See https://github.com/flycheck/flycheck/issues/1101 + (setq-local truncate-string-ellipsis "…")) + (tabulated-list-init-header)) + +(defvar-local flycheck-error-list-source-buffer nil + "The current source buffer of the error list.") +;; Needs to permanently local to preserve the source buffer across buffer +;; reversions +(put 'flycheck-error-list-source-buffer 'permanent-local t) + +(defun flycheck-error-list-set-source (buffer) + "Set BUFFER as the source buffer of the error list." + (flycheck-error-list-with-buffer + (setq flycheck-error-list-source-buffer buffer) + (flycheck-error-list-refresh))) + +(defun flycheck-error-list-update-source () + "Make the error list display errors from the current buffer. + +The update is skipped if the current buffer is the error list or +if the error list is already pointing to the current buffer." + (unless (memq (current-buffer) + (list (get-buffer flycheck-error-list-buffer) + (flycheck-error-list-with-buffer + flycheck-error-list-source-buffer))) + (flycheck-error-list-set-source (current-buffer)))) + +(defun flycheck-error-list-check-source () + "Trigger a syntax check in the source buffer of the error list." + (interactive) + (let ((buffer (get-buffer flycheck-error-list-source-buffer))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (flycheck-buffer))))) + +(define-button-type 'flycheck-error-list + 'action #'flycheck-error-list-goto-error + 'help-echo "mouse-1, RET: goto error" + 'face nil) + +(define-button-type 'flycheck-error-list-explain-error + 'action #'flycheck-error-list-explain-error + 'help-echo "mouse-1, RET: explain error") + +(defsubst flycheck-error-list-make-cell (text &optional face help-echo type) + "Make an error list cell with TEXT and FACE. + +If FACE is nil don't set a FACE on TEXT. If TEXT already has +face properties, do not specify a FACE. Note though, that if +TEXT gets truncated it will not inherit any previous face +properties. If you expect TEXT to be truncated in the error +list, do specify a FACE explicitly! + +If HELP-ECHO is non-nil, set a help-echo property on TEXT, with +value HELP-ECHO. This is convenient if you expect TEXT to be +truncated. + +The cell will have the type TYPE unless TYPE is nil, and the +default type `flycheck-error-list' will be used instead." + (append (list text 'type (if type type + 'flycheck-error-list)) + (and face (list 'face face)) + (and help-echo (list 'help-echo help-echo)))) + +(defsubst flycheck-error-list-make-number-cell (number face) + "Make a table cell for a NUMBER with FACE. + +Convert NUMBER to string, fontify it with FACE and return the +string with attached text properties." + (flycheck-error-list-make-cell + (if (numberp number) (number-to-string number) "") + face)) + +(defun flycheck-error-list-make-entry (error) + "Make a table cell for the given ERROR. + +Return a list with the contents of the table cell." + (let* ((level (flycheck-error-level error)) + (level-face (flycheck-error-level-error-list-face level)) + (filename (flycheck-error-filename error)) + (line (flycheck-error-line error)) + (column (flycheck-error-column error)) + (message (or (flycheck-error-message error) + (format "Unknown %S" level))) + (flushed-msg (flycheck-flush-multiline-message message)) + (id (flycheck-error-id error)) + (id-str (if id (format "%s" id) "")) + (checker (flycheck-error-checker error)) + (msg-and-checker + (flycheck-error-list-make-last-column flushed-msg checker)) + (explainer (flycheck-checker-get checker 'error-explainer))) + (list error + (vector (flycheck-error-list-make-cell + (if filename + (file-name-nondirectory filename) + "") + 'flycheck-error-list-filename) + (flycheck-error-list-make-number-cell + line 'flycheck-error-list-line-number) + (flycheck-error-list-make-number-cell + column 'flycheck-error-list-column-number) + (flycheck-error-list-make-cell + (symbol-name (flycheck-error-level error)) level-face) + ;; Error ID use a different face when an error-explainer is + ;; present + (flycheck-error-list-make-cell + id-str (if explainer 'flycheck-error-list-id-with-explainer + 'flycheck-error-list-id) + id-str 'flycheck-error-list-explain-error) + (flycheck-error-list-make-cell + msg-and-checker nil msg-and-checker))))) + +(defun flycheck-flush-multiline-message (msg) + "Prepare error message MSG for display in the error list. + +Prepend all lines of MSG except the first with enough space to +ensure that they line up properly once the message is displayed." + (let* ((spc-spec `(space . (:width ,flycheck--error-list-msg-offset))) + (spc (propertize " " 'display spc-spec)) + (rep (concat "\\1" spc "\\2"))) + (replace-regexp-in-string "\\([\r\n]+\\)\\(.\\)" rep msg))) + +(defun flycheck-error-list-current-errors () + "Read the list of errors in `flycheck-error-list-source-buffer'." + (when (buffer-live-p flycheck-error-list-source-buffer) + (buffer-local-value 'flycheck-current-errors + flycheck-error-list-source-buffer))) + +(defun flycheck-error-list-entries () + "Create the entries for the error list." + (-when-let* ((errors (flycheck-error-list-current-errors)) + (filtered (flycheck-error-list-apply-filter errors))) + (seq-map #'flycheck-error-list-make-entry filtered))) + +(defun flycheck-error-list-entry-< (entry1 entry2) + "Determine whether ENTRY1 is before ENTRY2 by location. + +See `flycheck-error-<'." + (flycheck-error-< (car entry1) (car entry2))) + +(defun flycheck-error-list-entry-level-< (entry1 entry2) + "Determine whether ENTRY1 is before ENTRY2 by level. + +See `flycheck-error-level-<'." + (not (flycheck-error-level-< (car entry1) (car entry2)))) + +(defvar flycheck-error-list-mode-line-map + (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'flycheck-error-list-mouse-switch-to-source) + map) + "Keymap for error list mode line.") + +(defun flycheck-error-list-propertized-source-name () + "Get the name of the current source buffer for the mode line. + +Propertize the name of the current source buffer for use in the +mode line indication of `flycheck-error-list-mode'." + (let ((name (replace-regexp-in-string + (rx "%") "%%" + (buffer-name flycheck-error-list-source-buffer) + 'fixed-case 'literal))) + (propertize name 'face 'mode-line-buffer-id + 'mouse-face 'mode-line-highlight + 'help-echo "mouse-1: switch to source" + 'local-map flycheck-error-list-mode-line-map))) + +(defun flycheck-error-list-mouse-switch-to-source (event) + "Switch to the error list source buffer of the EVENT window." + (interactive "e") + (save-selected-window + (when (eventp event) + (select-window (posn-window (event-start event)))) + (when (buffer-live-p flycheck-error-list-source-buffer) + (switch-to-buffer flycheck-error-list-source-buffer)))) + +(defun flycheck-get-error-list-window-list (&optional all-frames) + "Get all windows displaying the error list. + +ALL-FRAMES specifies the frames to consider, as in +`get-buffer-window-list'." + (-when-let (buf (get-buffer flycheck-error-list-buffer)) + (get-buffer-window-list buf nil all-frames))) + +(defun flycheck-get-error-list-window (&optional all-frames) + "Get a window displaying the error list, or nil if none. + +ALL-FRAMES specifies the frames to consider, as in +`get-buffer-window'." + (-when-let (buf (get-buffer flycheck-error-list-buffer)) + (get-buffer-window buf all-frames))) + +(defun flycheck-error-list-recenter-at (pos) + "Recenter the error list at POS." + (dolist (window (flycheck-get-error-list-window-list t)) + (with-selected-window window + (goto-char pos) + (let ((recenter-redisplay nil)) + (recenter))))) + +(defun flycheck-error-list-refresh () + "Refresh the current error list. + +Add all errors currently reported for the current +`flycheck-error-list-source-buffer', and recenter the error +list." + ;; We only refresh the error list, when it is visible in a window, and we + ;; select this window while reverting, because Tabulated List mode attempts to + ;; recenter the error at the old location, so it must have the proper window + ;; selected. + (-when-let (window (flycheck-get-error-list-window t)) + (with-selected-window window + (revert-buffer)) + (run-hooks 'flycheck-error-list-after-refresh-hook) + (let ((preserve-pos (eq (current-buffer) + (get-buffer flycheck-error-list-buffer)))) + ;; If the error list is the current buffer, don't recenter when + ;; highlighting + (flycheck-error-list-highlight-errors preserve-pos)))) + +(defun flycheck-error-list-mode-line-filter-indicator () + "Create a string representing the current error list filter." + (if flycheck-error-list-minimum-level + (format " [>= %s]" flycheck-error-list-minimum-level) + "")) + +(defun flycheck-error-list-set-filter (level) + "Restrict the error list to errors at level LEVEL or higher. + +LEVEL is either an error level symbol, or nil, to remove the filter." + (interactive + (list (flycheck-read-error-level + "Minimum error level (errors at lower levels will be hidden): "))) + (when (and level (not (flycheck-error-level-p level))) + (user-error "Invalid level: %s" level)) + (flycheck-error-list-with-buffer + (setq-local flycheck-error-list-minimum-level level) + (force-mode-line-update) + (flycheck-error-list-refresh) + (flycheck-error-list-recenter-at (point-min)))) + +(defun flycheck-error-list-reset-filter (&optional refresh) + "Remove local error filters and reset to the default filter. + +Interactively, or with non-nil REFRESH, refresh the error list." + (interactive '(t)) + (flycheck-error-list-with-buffer + (kill-local-variable 'flycheck-error-list-minimum-level) + (when refresh + (flycheck-error-list-refresh) + (flycheck-error-list-recenter-at (point-min)) + (force-mode-line-update)))) + +(defun flycheck-error-list-apply-filter (errors) + "Filter ERRORS according to `flycheck-error-list-minimum-level'." + (-if-let* ((min-level flycheck-error-list-minimum-level) + (min-severity (flycheck-error-level-severity min-level))) + (seq-filter (lambda (err) (>= (flycheck-error-level-severity + (flycheck-error-level err)) + min-severity)) + errors) + errors)) + +(defun flycheck-error-list-goto-error (&optional pos) + "Go to the location of the error at POS in the error list. + +POS defaults to `point'." + (interactive) + (-when-let* ((error (tabulated-list-get-id pos))) + (flycheck-jump-to-error error))) + +(defun flycheck-jump-to-error (error) + "Go to the location of ERROR." + (let* ((error-copy (copy-flycheck-error error)) + (filename (flycheck-error-filename error)) + (other-file-error (flycheck-relevant-error-other-file-p error)) + (buffer (if filename + (find-file-noselect filename) + (flycheck-error-buffer error)))) + (when (buffer-live-p buffer) + (setf (flycheck-error-buffer error-copy) buffer) + (flycheck-jump-in-buffer buffer error-copy) + ;; When jumping to an error in another file, it may not have + ;; this error available for highlighting yet, so we trigger a check + ;; if necessary. + (when other-file-error + (with-current-buffer buffer + ;; `seq-contains-p' is only in seq >= 2.21 + (unless (with-no-warnings + (seq-contains flycheck-current-errors error-copy 'equal)) + (when flycheck-mode + (flycheck-buffer)))))))) + +(defun flycheck-jump-in-buffer (buffer error) + "In BUFFER, jump to ERROR." + ;; FIXME: we assume BUFFER and the buffer of ERROR are the same. We don't + ;; need the first argument then. + (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer)) + ;; When called from within the error list, keep the error list, + ;; otherwise replace the current buffer. + (pop-to-buffer buffer 'other-window) + (switch-to-buffer buffer)) + (let ((pos (flycheck-error-pos error))) + (unless (eq (goto-char pos) (point)) + ;; If widening gets in the way of moving to the right place, remove it + ;; and try again + (widen) + (goto-char pos))) + ;; Re-highlight the errors. We have post-command-hook for that, but calls to + ;; `flycheck-jump-in-buffer' that come from other buffers (e.g. from the error + ;; list) won't trigger it. + (flycheck-error-list-highlight-errors 'preserve-pos)) + +(defun flycheck-error-list-explain-error (&optional pos) + "Explain the error at POS in the error list. + +POS defaults to `point'." + (interactive) + (-when-let* ((error (tabulated-list-get-id pos)) + (explainer (flycheck-checker-get (flycheck-error-checker error) + 'error-explainer))) + (flycheck-error-with-buffer error + (-when-let (explanation (funcall explainer error)) + (flycheck-display-error-explanation explanation))))) + +(defun flycheck-error-list-next-error-pos (pos &optional n) + "Starting from POS get the N'th next error in the error list. + +N defaults to 1. If N is negative, search for the previous error +instead. + +Get the beginning position of the N'th next error from POS, or +nil, if there is no next error." + (let ((n (or n 1))) + (if (>= n 0) + ;; Search forward + (while (and pos (/= n 0)) + (setq n (1- n)) + (setq pos (next-single-property-change pos 'tabulated-list-id))) + ;; Search backwards + (while (/= n 0) + (setq n (1+ n)) + ;; We explicitly give the limit here to explicitly have the minimum + ;; point returned, to be able to move to the first error (which starts + ;; at `point-min') + (setq pos (previous-single-property-change pos 'tabulated-list-id + nil (point-min))))) + pos)) + +(defun flycheck-error-list-previous-error (n) + "Go to the N'th previous error in the error list." + (interactive "P") + (flycheck-error-list-next-error (- (or n 1)))) + +(defun flycheck-error-list-next-error (n) + "Go to the N'th next error in the error list." + (interactive "P") + (let ((pos (flycheck-error-list-next-error-pos (point) n))) + (when (and pos (/= pos (point))) + (goto-char pos) + (save-selected-window + ;; Keep the error list selected, so that the user can navigate errors by + ;; repeatedly pressing n/p, without having to re-select the error list + ;; window. + (flycheck-error-list-goto-error))))) + +(defvar-local flycheck-error-list-highlight-overlays nil + "Error highlight overlays in the error list buffer.") +(put 'flycheck-error-list-highlight-overlays 'permanent-local t) + +(defun flycheck-error-list-highlight-errors (&optional preserve-pos) + "Highlight errors in the error list. + +Highlight all errors in the error list that are at point in the +source buffer, and on the same line as point. Then recenter the +error list to the highlighted error, unless PRESERVE-POS is +non-nil." + (when (get-buffer flycheck-error-list-buffer) + (with-current-buffer flycheck-error-list-buffer + (let ((current-errors + (when (buffer-live-p flycheck-error-list-source-buffer) + (with-current-buffer flycheck-error-list-source-buffer + (flycheck-overlay-errors-in (line-beginning-position) + (line-end-position)))))) + (let ((old-overlays flycheck-error-list-highlight-overlays) + (min-point (point-max)) + (max-point (point-min))) + ;; Display the new overlays first, to avoid re-display flickering + (setq flycheck-error-list-highlight-overlays nil) + (when current-errors + (let ((next-error-pos (point-min))) + (while next-error-pos + (let* ((beg next-error-pos) + (end (flycheck-error-list-next-error-pos beg)) + (err (tabulated-list-get-id beg))) + (when (member err current-errors) + (setq min-point (min min-point beg) + max-point (max max-point beg)) + (let ((ov (make-overlay beg + ;; Extend overlay to the beginning + ;; of the next line, to highlight + ;; the whole line + (or end (point-max))))) + (push ov flycheck-error-list-highlight-overlays) + (setf (overlay-get ov 'flycheck-error-highlight-overlay) + t) + (setf (overlay-get ov 'face) + 'flycheck-error-list-highlight))) + (setq next-error-pos end))))) + ;; Delete the old overlays + (seq-do #'delete-overlay old-overlays) + (when (and (not preserve-pos) current-errors) + ;; Move point to the middle error + (goto-char (+ min-point (/ (- max-point min-point) 2))) + (beginning-of-line) + ;; And recenter the error list at this position + (flycheck-error-list-recenter-at (point)))))))) + +(defun flycheck-list-errors () + "Show the error list for the current buffer." + (interactive) + (unless flycheck-mode + (user-error "Flycheck mode not enabled")) + ;; Create and initialize the error list + (unless (get-buffer flycheck-error-list-buffer) + (with-current-buffer (get-buffer-create flycheck-error-list-buffer) + (flycheck-error-list-mode))) + ;; Reset the error filter + (flycheck-error-list-reset-filter) + (let ((source (current-buffer))) + ;; Show the error list in a side window. Under some configurations of + ;; `display-buffer', this may select `flycheck-error-list-buffer' (see URL + ;; `https://github.com/flycheck/flycheck/issues/1776'). + (display-buffer flycheck-error-list-buffer) + ;; Adjust the source, causing a refresh + (flycheck-error-list-set-source source))) + +(defalias 'list-flycheck-errors 'flycheck-list-errors) + + +;;; Displaying errors in the current buffer +(defun flycheck-display-errors (errors) + "Display ERRORS using `flycheck-display-errors-function'." + (when flycheck-display-errors-function + (funcall flycheck-display-errors-function errors))) + +(defvar-local flycheck-display-error-at-point-timer nil + "Timer to automatically show errors.") + +(defun flycheck-cancel-error-display-error-at-point-timer () + "Cancel the error display timer for the current buffer." + (when flycheck-display-error-at-point-timer + (cancel-timer flycheck-display-error-at-point-timer) + (setq flycheck-display-error-at-point-timer nil))) + +(defun flycheck--error-display-tick () + "Return point and tick counter of current buffer." + (cons (point) (buffer-modified-tick))) + +(defvar-local flycheck--last-error-display-tick nil + "Value of `flycheck--error-display-tick' when errors were last displayed.") + +(defun flycheck-display-error-at-point () + "Display all the error messages at point." + (interactive) + ;; This function runs from a timer, so we must take care to not ignore any + ;; errors + (with-demoted-errors "Flycheck error display error: %s" + (flycheck-cancel-error-display-error-at-point-timer) + (setq flycheck--last-error-display-tick (flycheck--error-display-tick)) + (when flycheck-mode + (-when-let (errors (flycheck-overlay-errors-at (point))) + (flycheck-display-errors errors))))) + +(defun flycheck-display-error-at-point-soon () + "Display error messages at point, with a delay." + (setq flycheck--last-error-display-tick nil) + (flycheck-maybe-display-error-at-point-soon)) + +(defun flycheck-maybe-display-error-at-point-soon () + "Display error message at point with a delay, unless already displayed." + (flycheck-cancel-error-display-error-at-point-timer) + (when (and (not (equal flycheck--last-error-display-tick + (setq flycheck--last-error-display-tick + (flycheck--error-display-tick)))) + (flycheck-overlays-at (point))) + (setq flycheck-display-error-at-point-timer + (run-at-time flycheck-display-errors-delay nil + 'flycheck-display-error-at-point)))) + + +;;; Functions to display errors +(defconst flycheck-error-message-buffer "*Flycheck error messages*" + "The name of the buffer to show long error messages in.") + +(defun flycheck-error-message-buffer () + "Get the buffer object to show long error messages in. + +Get the buffer named by variable `flycheck-error-message-buffer', +or nil if the buffer does not exist." + (get-buffer flycheck-error-message-buffer)) + +(defun flycheck-may-use-echo-area-p () + "Determine whether the echo area may be used. + +The echo area may be used if the cursor is not in the echo area, +and if the echo area is not occupied by minibuffer input." + (not (or cursor-in-echo-area (active-minibuffer-window)))) + +(define-derived-mode flycheck-error-message-mode text-mode + "Flycheck error messages" + "Major mode for extended error messages.") + +(defun flycheck-display-error-messages (errors) + "Display the messages of ERRORS. + +Concatenate all non-nil messages of ERRORS as with +`flycheck-help-echo-all-error-messages', and display them with +`display-message-or-buffer', which shows the messages either in +the echo area or in a separate buffer, depending on the number of +lines. See Info node `(elisp)Displaying Messages' for more +information. + +In the latter case, show messages in the buffer denoted by +variable `flycheck-error-message-buffer'." + (when (and errors (flycheck-may-use-echo-area-p)) + (let ((message (flycheck-help-echo-all-error-messages errors))) + (display-message-or-buffer + message flycheck-error-message-buffer 'not-this-window) + ;; We cannot rely on `display-message-or-buffer' returning the right + ;; window. See URL `https://github.com/flycheck/flycheck/issues/1643'. + (-when-let (buf (get-buffer flycheck-error-message-buffer)) + (with-current-buffer buf + (unless (derived-mode-p 'flycheck-error-message-mode) + (flycheck-error-message-mode))))))) + +(defun flycheck-display-error-messages-unless-error-list (errors) + "Show messages of ERRORS unless the error list is visible. + +Like `flycheck-display-error-messages', but only if the error +list (see `flycheck-list-errors') is not visible in any window in +the current frame." + (unless (flycheck-get-error-list-window 'current-frame) + (flycheck-display-error-messages errors))) + +(defun flycheck-hide-error-buffer () + "Hide the Flycheck error buffer if necessary. + +Hide the error buffer if there is no error under point." + (-when-let* ((buffer (flycheck-error-message-buffer)) + (window (get-buffer-window buffer))) + (unless (flycheck-overlays-at (point)) + ;; save-selected-window prevents `quit-window' from changing the current + ;; buffer (see https://github.com/flycheck/flycheck/issues/648). + (save-selected-window + (quit-window nil window))))) + + +;;; Working with errors +(defun flycheck-copy-errors-as-kill (pos &optional formatter) + "Copy each error at POS into kill ring, using FORMATTER. + +FORMATTER is a function to turn an error into a string, +defaulting to `flycheck-error-message'. + +Interactively, use `flycheck-error-format-message-and-id' as +FORMATTER with universal prefix arg, and `flycheck-error-id' with +normal prefix arg, i.e. copy the message and the ID with +universal prefix arg, and only the id with normal prefix arg." + (interactive (list (point) + (pcase current-prefix-arg + ((pred not) #'flycheck-error-message) + ((pred consp) #'flycheck-error-format-message-and-id) + (_ #'flycheck-error-id)))) + (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message) + (flycheck-overlay-errors-at pos))))) + (when messages + (seq-do #'kill-new (reverse messages)) + (message (string-join messages "\n"))))) + +(defun flycheck-explain-error-at-point () + "Display an explanation for the first explainable error at point. + +The first explainable error at point is the first error at point +with a non-nil `:error-explainer' function defined in its +checker. The `:error-explainer' function is then called with +this error to produce the explanation to display." + (interactive) + (-when-let* ((first-error + ;; Get the first error at point that has an `error-explainer'. + (seq-find (lambda (error) + (flycheck-checker-get + (flycheck-error-checker error) 'error-explainer)) + (flycheck-overlay-errors-at (point)))) + (explainer + (flycheck-checker-get (flycheck-error-checker first-error) + 'error-explainer)) + (explanation (funcall explainer first-error))) + (flycheck-display-error-explanation explanation))) + +(defconst flycheck-explain-error-buffer "*Flycheck error explanation*" + "The name of the buffer to show error explanations.") + +(define-derived-mode flycheck-explain-error-mode help-mode + "Error explanation" + "Major mode for displaying error explanations." + (setq buffer-read-only t)) + +(defun flycheck-display-error-explanation (explanation) + "Display the EXPLANATION for an error." + (pcase explanation + (`nil) + (`(url . ,url) (browse-url url)) + (_ (let ((inhibit-read-only t) + (standard-output (temp-buffer-window-setup + flycheck-explain-error-buffer))) + (with-current-buffer standard-output + (flycheck-explain-error-mode)) + (cond + ((functionp explanation) (funcall explanation)) + ((stringp explanation) (princ explanation)) + (t (error "Unsupported error explanation: %S" explanation))) + (display-message-or-buffer standard-output nil 'not-this-window))))) + + +;;; Syntax checkers using external commands +(defun flycheck-command-argument-p (arg) + "Check whether ARG is a valid command argument." + (pcase arg + ((pred stringp) t) + ((or `source `source-inplace `source-original) t) + (`(,(or `source `source-inplace) ,suffix) + (stringp suffix)) + ((or `temporary-directory `temporary-file-name) t) + (`null-device t) + (`(config-file ,option-name ,config-file-var) + (and (stringp option-name) + (symbolp config-file-var))) + (`(config-file ,option-name ,config-file-var ,prepender) + (and (stringp option-name) + (symbolp config-file-var) + (symbolp prepender))) + (`(,(or `option `option-list) ,option-name ,option-var) + (and (stringp option-name) + (symbolp option-var))) + (`(,(or `option `option-list) ,option-name ,option-var ,prepender) + (and (stringp option-name) + (symbolp option-var) + (symbolp prepender))) + (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter) + (and (stringp option-name) + (symbolp option-var) + (symbolp prepender) + (symbolp filter))) + (`(option-flag ,option-name ,option-var) + (and (stringp option-name) + (symbolp option-var))) + (`(eval ,_) t) + (_ nil))) + +(defun flycheck-compute-working-directory (checker) + "Get the default working directory for CHECKER. + +Compute the value of `default-directory' for the invocation of +the syntax checker command, by calling the function in the +`working-directory' property of CHECKER, with CHECKER as sole +argument, and returning its value. Signal an error if the +function returns a non-existing working directory. + +If the property is undefined or if the function returns nil +return the `default-directory' of the current buffer." + (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory)) + (directory (or (and def-directory-fn + (funcall def-directory-fn checker)) + ;; Default to the `default-directory' of the current + ;; buffer + default-directory))) + (unless (file-exists-p directory) + (error ":working-directory %s of syntax checker %S does not exist" + directory checker)) + directory)) + +;;;###autoload +(defun flycheck-define-command-checker (symbol docstring &rest properties) + "Define SYMBOL as syntax checker to run a command. + +Define SYMBOL as generic syntax checker via +`flycheck-define-generic-checker', which uses an external command +to check the buffer. SYMBOL and DOCSTRING are the same as for +`flycheck-define-generic-checker'. + +In addition to the properties understood by +`flycheck-define-generic-checker', the following PROPERTIES +constitute a command syntax checker. Unless otherwise noted, all +properties are mandatory. Note that the default `:error-filter' +of command checkers is `flycheck-sanitize-errors'. + +`:command COMMAND' + The command to run for syntax checking. + + COMMAND is a list of the form `(EXECUTABLE [ARG ...])'. + + EXECUTABLE is a string with the executable of this syntax + checker. It can be overridden with the variable + `flycheck-SYMBOL-executable'. Note that this variable is + NOT implicitly defined by this function. Use + `flycheck-def-executable-var' to define this variable. + + Each ARG is an argument to the executable, either as string, + or as special symbol or form for + `flycheck-substitute-argument', which see. + +`:error-patterns PATTERNS' + A list of patterns to parse the output of the `:command'. + + Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where + LEVEL is a Flycheck error level (see + `flycheck-define-error-level'), followed by one or more RX + `SEXP's which parse an error of that level and extract line, + column, file name and the message. + + See `rx' for general information about RX, and + `flycheck-rx-to-string' for some special RX forms provided + by Flycheck. + + All patterns are applied in the order of declaration to the + whole output of the syntax checker. Output already matched + by a pattern will not be matched by subsequent patterns. In + other words, the first pattern wins. + + This property is optional. If omitted, however, an + `:error-parser' is mandatory. + +`:error-parser FUNCTION' + A function to parse errors with. + + The function shall accept three arguments OUTPUT CHECKER + BUFFER. OUTPUT is the syntax checker output as string, + CHECKER the syntax checker that was used, and BUFFER a + buffer object representing the checked buffer. The function + must return a list of `flycheck-error' objects parsed from + OUTPUT. + + This property is optional. If omitted, it defaults to + `flycheck-parse-with-patterns'. In this case, + `:error-patterns' is mandatory. + +`:standard-input t' + Whether to send the buffer contents on standard input. + + If this property is given and has a non-nil value, send the + contents of the buffer on standard input. + + Defaults to nil. + +Note that you may not give `:start', `:interrupt', and +`:print-doc' for a command checker. You can give a custom +`:verify' function, though, whose results will be appended to the +default `:verify' function of command checkers." + (declare (indent 1) + (doc-string 2)) + (dolist (prop '(:start :interrupt :print-doc)) + (when (plist-get properties prop) + (error "%s not allowed in definition of command syntax checker %s" + prop symbol))) + + (unless (plist-get properties :error-filter) + ;; Default to `flycheck-sanitize-errors' as error filter + (setq properties (plist-put properties :error-filter + #'flycheck-sanitize-errors))) + (let ((verify-fn (plist-get properties :verify))) + (setq properties + (plist-put properties :verify + (lambda (checker) + (append (flycheck-verify-command-checker checker) + (and verify-fn + (funcall verify-fn checker))))))) + + (let ((command (plist-get properties :command)) + (patterns (plist-get properties :error-patterns)) + (parser (or (plist-get properties :error-parser) + #'flycheck-parse-with-patterns)) + (enabled (plist-get properties :enabled)) + (standard-input (plist-get properties :standard-input))) + (unless command + (error "Missing :command in syntax checker %s" symbol)) + (unless (stringp (car command)) + (error "Command executable for syntax checker %s must be a string: %S" + symbol (car command))) + (dolist (arg (cdr command)) + (unless (flycheck-command-argument-p arg) + (error "Invalid command argument %S in syntax checker %s" arg symbol))) + (when (and (eq parser 'flycheck-parse-with-patterns) + (not patterns)) + (error "Missing :error-patterns in syntax checker %s" symbol)) + + (setq properties + ;; Automatically disable command checkers if the executable does not + ;; exist. + (plist-put properties :enabled + (lambda () + (and (flycheck-find-checker-executable symbol) + (flycheck-temp-files-writable-p symbol) + (or (not enabled) (funcall enabled)))))) + + (apply #'flycheck-define-generic-checker symbol docstring + :start #'flycheck-start-command-checker + :interrupt #'flycheck-interrupt-command-checker + :print-doc #'flycheck-command-checker-print-doc + properties) + + ;; Pre-compile all errors patterns into strings, so that we don't need to do + ;; that on each error parse + (let ((patterns (seq-map (lambda (p) + (cons (flycheck-rx-to-string `(and ,@(cdr p)) + 'no-group) + (car p))) + patterns))) + (pcase-dolist (`(,prop . ,value) + `((command . ,command) + (error-parser . ,parser) + (error-patterns . ,patterns) + (standard-input . ,standard-input))) + (setf (flycheck-checker-get symbol prop) value))))) + +(eval-and-compile + ;; Make this function available during byte-compilation, since we need it + ;; at macro expansion of `flycheck-def-executable-var'. + (defun flycheck-checker-executable-variable (checker) + "Get the executable variable of CHECKER. + +The executable variable is named `flycheck-CHECKER-executable'." + (intern (format "flycheck-%s-executable" checker)))) + +(defun flycheck-checker-default-executable (checker) + "Get the default executable of CHECKER." + (car (flycheck-checker-get checker 'command))) + +(defun flycheck-checker-executable (checker) + "Get the command executable of CHECKER. + +The executable is either the value of the variable +`flycheck-CHECKER-executable', or the default executable given in +the syntax checker definition, if the variable is nil." + (let ((var (flycheck-checker-executable-variable checker))) + (or (and (boundp var) (symbol-value var)) + (flycheck-checker-default-executable checker)))) + +(defun flycheck-find-checker-executable (checker) + "Get the full path of the executable of CHECKER. + +Return the full absolute path to the executable of CHECKER, or +nil if the executable does not exist." + (funcall flycheck-executable-find (flycheck-checker-executable checker))) + +(defun flycheck-call-checker-process + (checker infile destination error &rest args) + "Call CHECKER's executable with ARGS. + +Return nil (or raise an error if ERROR is non-nil) when CHECKER's +executable cannot be found, and return a numeric exit status or a +signal description string otherwise. CHECKER's input is taken +from INFILE, and its output is sent to DESTINATION, as in +`call-process'." + (-if-let (executable (flycheck-find-checker-executable checker)) + (condition-case err + (apply #'call-process executable infile destination nil args) + (error (when error (signal (car err) (cdr err))))) + (when error + (user-error "Cannot find `%s' using `flycheck-executable-find'" + (flycheck-checker-executable checker))))) + +(defun flycheck-call-checker-process-for-output + (checker infile error &rest args) + "Call CHECKER's executable with ARGS and return its output. + +Call `flycheck-call-checker-process' with INFILE, ERROR, and +ARGS. If it returns 0, return the process' output. Otherwise, +return nil or throw an error. + +This function is similar to `flycheck-call-checker-process' +called in a `with-output-to-string' block, but it takes care of +the error checking automatically." + (let ((temp (generate-new-buffer " *temp*"))) + (unwind-protect + ;; We need to call the checker process in the right buffer, so that it + ;; uses the right exec-path, checker executable, etc. See URL + ;; `https://github.com/flycheck/flycheck/issues/1770'. + (let ((exit-code (apply #'flycheck-call-checker-process + checker infile temp error args)) + (output (with-current-buffer temp (buffer-string)))) + (if (eql 0 exit-code) output + (when error + (error "Process %s failed with %S (%s)" + checker exit-code output)))) + (kill-buffer temp)))) + +(defun flycheck-checker-arguments (checker) + "Get the command arguments of CHECKER." + (cdr (flycheck-checker-get checker 'command))) + +(defun flycheck-substitute-argument (arg checker) + "Substitute ARG for CHECKER. + +Return a list of real arguments for the executable of CHECKER, +substituted for the symbolic argument ARG. Single arguments, +e.g. if ARG is a literal strings, are wrapped in a list. + +ARG may be one of the following forms: + +STRING + Return ARG unchanged. + +`source', `source-inplace' + Create a temporary file to check and return its path. With + `source-inplace' create the temporary file in the same + directory as the original file. The value of + `flycheck-temp-prefix' is used as prefix of the file name. + + With `source', try to retain the non-directory component of + the buffer's file name in the temporary file. + + `source' is the preferred way to pass the input file to a + syntax checker. `source-inplace' should only be used if the + syntax checker needs other files from the source directory, + such as include files in C. + +`(source SUFFIX)', `(source-inplace SUFFIX)' + Like `source' and `source-inplace', but ensure generated + file names end with the given suffix. Use this when the + checker requires that file names on its command line have a + certain suffix (file extension). + +`source-original' + Return the path of the actual file to check, or an empty + string if the buffer has no file name. + + Note that the contents of the file may not be up to date + with the contents of the buffer to check. Do not use this + as primary input to a checker, unless absolutely necessary. + + When using this symbol as primary input to the syntax + checker, add `flycheck-buffer-saved-p' to the `:predicate'. + +`temporary-directory' + Create a unique temporary directory and return its path. + +`temporary-file-name' + Return a unique temporary filename. The file is *not* + created. + + To ignore the output of syntax checkers, try symbol + `null-device' first. + +symbol `null-device' + Return the value of variable `null-device', i.e the system + null device. + + Use this option to ignore the output of a syntax checker. + If the syntax checker cannot handle the null device, or + won't write to an existing file, try `temporary-file-name' + instead. + +`(config-file OPTION VARIABLE [PREPEND-FN])' + Search the configuration file bound to VARIABLE with + `flycheck-locate-config-file' and return a list of arguments + that pass this configuration file to the syntax checker, or + nil if the configuration file was not found. + + PREPEND-FN is called with the OPTION and the located + configuration file, and should return OPTION prepended + before the file, either a string or as list. If omitted, + PREPEND-FN defaults to `list'. + +`(option OPTION VARIABLE [PREPEND-FN [FILTER]])' + Retrieve the value of VARIABLE and return a list of + arguments that pass this value as value for OPTION to the + syntax checker. + + PREPEND-FN is called with the OPTION and the value of + VARIABLE, and should return OPTION prepended before the + file, either a string or as list. If omitted, PREPEND-FN + defaults to `list'. + + FILTER is an optional function to be applied to the value of + VARIABLE before prepending. This function must return nil + or a string. In the former case, return nil. In the latter + case, return a list of arguments as described above. + +`(option-list OPTION VARIABLE [PREPEND-FN [FILTER]])' + Retrieve the value of VARIABLE, which must be a list, + and prepend OPTION before each item in this list, using + PREPEND-FN. + + PREPEND-FN is called with the OPTION and each item of the + list as second argument, and should return OPTION prepended + before the item, either as string or as list. If omitted, + PREPEND-FN defaults to `list'. + + FILTER is an optional function to be applied to each item in + the list before prepending OPTION. It shall return the + option value for each item as string, or nil, if the item is + to be ignored. + +`(option-flag OPTION VARIABLE)' + Retrieve the value of VARIABLE and return OPTION, if the + value is non-nil. Otherwise return nil. + +`(eval FORM)' + Return the result of evaluating FORM in the buffer to be + checked. FORM must either return a string or a list of + strings, or nil to indicate that nothing should be + substituted for CELL. For all other return types, signal an + error + + _No_ further substitutions are performed, neither in FORM + before it is evaluated, nor in the result of evaluating + FORM. + +In all other cases, signal an error. + +Note that substitution is *not* recursive. No symbols or cells +are substituted within the body of cells!" + (pcase arg + ((pred stringp) (list arg)) + (`source + (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-system))) + (`source-inplace + (list (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace))) + (`(source ,suffix) + (list (flycheck-save-buffer-to-temp + (lambda (filename) (flycheck-temp-file-system filename suffix))))) + (`(source-inplace ,suffix) + (list (flycheck-save-buffer-to-temp + (lambda (filename) (flycheck-temp-file-inplace filename suffix))))) + (`source-original (list (or (buffer-file-name) ""))) + (`temporary-directory (list (flycheck-temp-dir-system))) + (`temporary-file-name + (let ((directory (flycheck-temp-dir-system))) + (list (make-temp-name (expand-file-name "flycheck" directory))))) + (`null-device (list null-device)) + (`(config-file ,option-name ,file-name-var) + (-when-let* ((value (symbol-value file-name-var)) + (file-name (flycheck-locate-config-file value checker))) + (flycheck-prepend-with-option option-name (list file-name)))) + (`(config-file ,option-name ,file-name-var ,prepend-fn) + (-when-let* ((value (symbol-value file-name-var)) + (file-name (flycheck-locate-config-file value checker))) + (flycheck-prepend-with-option option-name (list file-name) prepend-fn))) + (`(option ,option-name ,variable) + (-when-let (value (symbol-value variable)) + (unless (stringp value) + (error "Value %S of %S for option %s is not a string" + value variable option-name)) + (flycheck-prepend-with-option option-name (list value)))) + (`(option ,option-name ,variable ,prepend-fn) + (-when-let (value (symbol-value variable)) + (unless (stringp value) + (error "Value %S of %S for option %s is not a string" + value variable option-name)) + (flycheck-prepend-with-option option-name (list value) prepend-fn))) + (`(option ,option-name ,variable ,prepend-fn ,filter) + (-when-let (value (funcall filter (symbol-value variable))) + (unless (stringp value) + (error "Value %S of %S (filter: %S) for option %s is not a string" + value variable filter option-name)) + (flycheck-prepend-with-option option-name (list value) prepend-fn))) + (`(option-list ,option-name ,variable) + (let ((value (symbol-value variable))) + (unless (and (listp value) (seq-every-p #'stringp value)) + (error "Value %S of %S for option %S is not a list of strings" + value variable option-name)) + (flycheck-prepend-with-option option-name value))) + (`(option-list ,option-name ,variable ,prepend-fn) + (let ((value (symbol-value variable))) + (unless (and (listp value) (seq-every-p #'stringp value)) + (error "Value %S of %S for option %S is not a list of strings" + value variable option-name)) + (flycheck-prepend-with-option option-name value prepend-fn))) + (`(option-list ,option-name ,variable ,prepend-fn ,filter) + (let ((value (delq nil (seq-map filter (symbol-value variable))))) + (unless (and (listp value) (seq-every-p #'stringp value)) + (error "Value %S of %S for option %S is not a list of strings" + value variable option-name)) + (flycheck-prepend-with-option option-name value prepend-fn))) + (`(option-flag ,option-name ,variable) + (when (symbol-value variable) + (list option-name))) + (`(eval ,form) + (let ((result (eval form))) + (cond + ((and (listp result) (seq-every-p #'stringp result)) result) + ((stringp result) (list result)) + (t (error "Invalid result from evaluation of %S: %S" form result))))) + (_ (error "Unsupported argument %S" arg)))) + +(defun flycheck-checker-substituted-arguments (checker) + "Get the substituted arguments of a CHECKER. + +Substitute each argument of CHECKER using +`flycheck-substitute-argument'. This replaces any special +symbols in the command." + (apply #'append + (seq-map (lambda (arg) (flycheck-substitute-argument arg checker)) + (flycheck-checker-arguments checker)))) + +(defun flycheck--process-send-buffer-contents-chunked (process) + "Send contents of current buffer to PROCESS in small batches. + +Send the entire buffer to the standard input of PROCESS in chunks +of 4096 characters. Chunking is done in Emacs Lisp, hence this +function is probably far less efficient than +`send-process-region'. Use only when required." + (let ((from (point-min))) + (while (< from (point-max)) + (let ((to (min (+ from 4096) (point-max)))) + (process-send-region process from to) + (setq from to))))) + +(defvar flycheck-chunked-process-input + ;; Chunk process output on Windows to work around + ;; https://github.com/flycheck/flycheck/issues/794 and + ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344. The presence of + ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1) where pipe + ;; writes on Windows are fixed. + ;; + ;; TODO: Remove option and chunking when dropping Emacs 24 support, see + ;; https://github.com/flycheck/flycheck/issues/856 + (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size))) + "If non-nil send process input in small chunks. + +If this variable is non-nil `flycheck-process-send-buffer' sends +buffer contents in small chunks. + +Defaults to nil, except on Windows to work around Emacs bug +#22344.") + +(defun flycheck-process-send-buffer (process) + "Send all contents of current buffer to PROCESS. + +Sends all contents of the current buffer to the standard input of +PROCESS, and terminates standard input with EOF. + +If `flycheck-chunked-process-input' is non-nil, send buffer +contents in chunks via +`flycheck--process-send-buffer-contents-chunked', which see. +Otherwise use `process-send-region' to send all contents at once +and rely on Emacs' own buffering and chunking." + (save-restriction + (widen) + (if flycheck-chunked-process-input + (flycheck--process-send-buffer-contents-chunked process) + (process-send-region process (point-min) (point-max)))) + (process-send-eof process)) + +(defun flycheck--wrap-command (prog args) + "Wrap PROG and ARGS using `flycheck-command-wrapper-function'." + ;; We don't call `flycheck-executable-find' on the output of the wrapper + ;; function, since it might not expect it (an executable-find function + ;; designed to find binaries in a sandbox could get confused if we asked it + ;; about the sandboxing program itself). + (funcall flycheck-command-wrapper-function (cons prog args))) + +(defun flycheck-start-command-checker (checker callback) + "Start a command CHECKER with CALLBACK." + (let (process) + (condition-case err + (let* ((program (flycheck-find-checker-executable checker)) + (args (flycheck-checker-substituted-arguments checker)) + (command (flycheck--wrap-command program args)) + (sentinel-events nil) + ;; Use pipes to receive output from the syntax checker. They are + ;; more efficient and more robust than PTYs, which Emacs uses by + ;; default, and since we don't need any job control features, we + ;; can easily use pipes. + (process-connection-type nil)) + ;; We pass do not associate the process with any buffer, by + ;; passing nil for the BUFFER argument of `start-process'. + ;; Instead, we just remember the buffer being checked in a + ;; process property (see below). This neatly avoids all + ;; side-effects implied by attached a process to a buffer, which + ;; may cause conflicts with other packages. + ;; + ;; See https://github.com/flycheck/flycheck/issues/298 for an + ;; example for such a conflict. + (setq process (apply 'start-process (format "flycheck-%s" checker) + nil command)) + ;; Process sentinels can be called while sending input to the process. + ;; We want to record errors raised by process-send before calling + ;; `flycheck-handle-signal', so initially just accumulate events. + (setf (process-sentinel process) + (lambda (_ event) (push event sentinel-events))) + (setf (process-filter process) #'flycheck-receive-checker-output) + (set-process-query-on-exit-flag process nil) + ;; Remember the syntax checker, the buffer and the callback + (process-put process 'flycheck-checker checker) + (process-put process 'flycheck-callback callback) + (process-put process 'flycheck-buffer (current-buffer)) + ;; The default directory is bound in the `flycheck-syntax-check-start' + ;; function. + (process-put process 'flycheck-working-directory default-directory) + ;; Track the temporaries created by argument substitution in the + ;; process itself, to get rid of the global state ASAP. + (process-put process 'flycheck-temporaries flycheck-temporaries) + (setq flycheck-temporaries nil) + ;; Send the buffer to the process on standard input, if enabled. + (when (flycheck-checker-get checker 'standard-input) + (condition-case err + (flycheck-process-send-buffer process) + ;; Some checkers exit before reading all input, causing errors + ;; such as a `file-error' for a closed pipe, or a plain “no longer + ;; connected to pipe; closed it” error for a disconnection. We + ;; report them if needed in `flycheck-finish-checker-process' (see + ;; `https://github.com/flycheck/flycheck/issues/1278'). + (error (process-put process 'flycheck-error err)))) + ;; Set the actual sentinel and process any events that might have + ;; happened while we were sending input. + (setf (process-sentinel process) #'flycheck-handle-signal) + (dolist (event (nreverse sentinel-events)) + (flycheck-handle-signal process event)) + ;; Return the process. + process) + (error + ;; In case of error, clean up our resources, and report the error back to + ;; Flycheck. + (flycheck-safe-delete-temporaries) + (when process + ;; No need to explicitly delete the temporary files of the process, + ;; because deleting runs the sentinel, which will delete them anyway. + (delete-process process)) + (signal (car err) (cdr err)))))) + +(defun flycheck-interrupt-command-checker (_checker process) + "Interrupt a PROCESS." + ;; Deleting the process always triggers the sentinel, which does the cleanup + (when process + (delete-process process))) + +(defun flycheck-command-checker-print-doc (checker) + "Print additional documentation for a command CHECKER." + (let ((executable (flycheck-checker-default-executable checker)) + (config-file-var (flycheck-checker-get checker 'config-file-var)) + (option-vars (seq-sort #'string< + (flycheck-checker-get checker 'option-vars)))) + (princ "\n") + + (let ((doc-start (with-current-buffer standard-output (point-max)))) + ;; Track the start of our documentation so that we can re-indent it + ;; properly + (princ " This syntax checker executes \"") + (princ executable) + (princ "\"") + (when config-file-var + (princ ", using a configuration file from `") + (princ (symbol-name config-file-var)) + (princ "'")) + (princ ". The executable can be overridden with `") + (princ (symbol-name (flycheck-checker-executable-variable checker))) + (princ "'.") + + (with-current-buffer standard-output + (save-excursion + (fill-region-as-paragraph doc-start (point-max))))) + (princ "\n") + (when option-vars + (princ + "\n This syntax checker can be configured with these options:\n\n") + (dolist (var option-vars) + (princ (format " * `%s'\n" var)))))) + +(defun flycheck-verify-command-checker (checker) + "Verify a command CHECKER in the current buffer. + +Return a list of `flycheck-verification-result' objects for +CHECKER." + (let ((executable (flycheck-find-checker-executable checker)) + (config-file-var (flycheck-checker-get checker 'config-file-var))) + `( + ,(flycheck-verification-result-new + :label "executable" + :message (if executable (format "Found at %s" executable) "Not found") + :face (if executable 'success '(bold error))) + ,@(when config-file-var + (let* ((value (symbol-value config-file-var)) + (path (and value (flycheck-locate-config-file value checker)))) + (list (flycheck-verification-result-new + :label "configuration file" + :message (if path (format "Found at %S" path) "Not found") + :face (if path 'success 'warning))))) + ,@(when (not (flycheck-temp-files-writable-p checker)) + (list (flycheck-verification-result-new + :label "temp directory" + :message (format "%s is not writable" + (flycheck-temp-directory checker)) + :face 'error)))))) + + +;;; Process management for command syntax checkers +(defun flycheck-receive-checker-output (process output) + "Receive a syntax checking PROCESS OUTPUT." + (push output (process-get process 'flycheck-pending-output))) + +(defun flycheck-get-output (process) + "Get the complete output of PROCESS." + (with-demoted-errors "Error while retrieving process output: %S" + (let ((pending-output (process-get process 'flycheck-pending-output))) + (apply #'concat (nreverse pending-output))))) + +(defun flycheck-handle-signal (process _event) + "Handle a signal from the syntax checking PROCESS. + +_EVENT is ignored." + (when (memq (process-status process) '(signal exit)) + (let ((files (process-get process 'flycheck-temporaries)) + (buffer (process-get process 'flycheck-buffer)) + (callback (process-get process 'flycheck-callback)) + (cwd (process-get process 'flycheck-working-directory)) + (err (process-get process 'flycheck-error))) + ;; Delete the temporary files + (seq-do #'flycheck-safe-delete files) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (condition-case err + (pcase (process-status process) + (`signal + (funcall callback 'interrupted)) + (`exit + (flycheck-finish-checker-process + (process-get process 'flycheck-checker) + (or err (process-exit-status process)) + files + (flycheck-get-output process) callback cwd))) + ((debug error) + (funcall callback 'errored (error-message-string err))))))))) + +(defun flycheck-finish-checker-process + (checker exit-status files output callback cwd) + "Finish a checker process from CHECKER with EXIT-STATUS. + +EXIT-STATUS can be a number or an arbitrary form (if it is not 0, +a `suspicious' status is reported to CALLBACK). + +FILES is a list of files given as input to the checker. OUTPUT +is the output of the syntax checker. CALLBACK is the status +callback to use for reporting. + +Parse the OUTPUT and report an appropriate error status. + +Resolve all errors in OUTPUT using CWD as working directory." + (let ((errors (flycheck-parse-output output checker (current-buffer)))) + (when (and (not (equal exit-status 0)) (null errors)) + ;; Warn about a suspicious result from the syntax checker. We do right + ;; after parsing the errors, before filtering, because a syntax checker + ;; might report errors from other files (e.g. includes) even if there + ;; are no errors in the file being checked. + (funcall callback 'suspicious + (format "Flycheck checker %S returned %S, but \ +its output contained no errors: %s\nTry installing a more \ +recent version of %S, and please open a bug report if the issue \ +persists in the latest release. Thanks!" checker exit-status +output checker))) + (funcall callback 'finished + ;; Fix error file names, by substituting them backwards from the + ;; temporaries. + (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd)) + errors)))) + + +;;; Executables of command checkers. +(defmacro flycheck-def-executable-var (checker default-executable) + "Define the executable variable for CHECKER. + +DEFAULT-EXECUTABLE is the default executable. It is only used in +the docstring of the variable. + +The variable is defined with `defcustom' in the +`flycheck-executables' group. It's also defined to be risky as +file-local variable, to avoid arbitrary executables being used +for syntax checking." + (let ((executable-var (flycheck-checker-executable-variable checker))) + `(progn + (defcustom ,executable-var nil + ,(format "The executable of the %s syntax checker. + +Either a string containing the name or the path of the +executable, or nil to use the default executable from the syntax +checker declaration. + +The default executable is %S." checker default-executable) + :type '(choice (const :tag "Default executable" nil) + (string :tag "Name or path")) + :group 'flycheck-executables + :risky t)))) + +(defun flycheck-set-checker-executable (checker &optional executable) + "Set the executable of CHECKER in the current buffer. + +CHECKER is a syntax checker symbol. EXECUTABLE is a string with +the name of an executable or the path to an executable file, which +is to be used as executable for CHECKER. If omitted or nil, +reset the executable of CHECKER. + +Interactively, prompt for a syntax checker and an executable +file, and set the executable of the selected syntax checker. +With prefix arg, prompt for a syntax checker only, and reset the +executable of the select checker to the default. + +Set the executable variable of CHECKER, that is, +`flycheck-CHECKER-executable' to EXECUTABLE. Signal +`user-error', if EXECUTABLE does not denote a command or an +executable file. + +This command is intended for interactive use only. In Lisp, just +`let'-bind the corresponding variable, or set it directly. Use +`flycheck-checker-executable-variable' to obtain the executable +variable symbol for a syntax checker." + (declare (interactive-only "Set the executable variable directly instead")) + (interactive + (let* ((checker (flycheck-read-checker "Syntax checker: ")) + (default-executable (flycheck-checker-default-executable checker)) + (executable (if current-prefix-arg + nil + (read-file-name "Executable: " nil default-executable + nil nil flycheck-executable-find)))) + (list checker executable))) + (when (and executable (not (funcall flycheck-executable-find executable))) + (user-error "%s is no executable" executable)) + (let ((variable (flycheck-checker-executable-variable checker))) + (set (make-local-variable variable) executable))) + + +;;; Configuration files and options for command checkers +(defun flycheck-register-config-file-var (var checkers) + "Register VAR as config file var for CHECKERS. + +CHECKERS is a single syntax checker or a list thereof." + (when (symbolp checkers) + (setq checkers (list checkers))) + (dolist (checker checkers) + (setf (flycheck-checker-get checker 'config-file-var) var))) + +;;;###autoload +(defmacro flycheck-def-config-file-var (symbol checker &optional file-name + &rest custom-args) + "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME. + +SYMBOL is declared as customizable variable using `defcustom', to +provide configuration files for the given syntax CHECKER. +CUSTOM-ARGS are forwarded to `defcustom'. + +FILE-NAME is the initial value of the new variable. If omitted, +the default value is nil. It can be either a string or a list of +strings. + +Use this together with the `config-file' form in the `:command' +argument to `flycheck-define-checker'." + (declare (indent 3)) + `(progn + (defcustom ,symbol ,file-name + ,(format "Configuration file for `%s'. + +If set to a string, locate the configuration file using the +functions from `flycheck-locate-config-file-functions'. If the +file is found pass it to the syntax checker as configuration +file. + +If no configuration file is found, or if this variable is set to +nil, invoke the syntax checker without a configuration file. + +Use this variable as file-local variable if you need a specific +configuration file for a buffer." checker) + :type '(choice (const :tag "No configuration file" nil) + (string :tag "File name or path") + (repeat :tag "File names or paths" string)) + :safe #'flycheck-string-or-string-list-p + :group 'flycheck-config-files + ,@custom-args) + (flycheck-register-config-file-var ',symbol ',checker))) + +(defun flycheck-locate-config-file (filenames checker) + "Locate the configuration file for CHECKER, based on FILENAMES. + +FILENAMES can be either a single file, or a list. Each filename +is passed to all `flycheck-locate-config-file-functions', until +one returns non-nil. + +Return the absolute path of the configuration file, or nil if no +configuration file was found." + (when (stringp filenames) + (setq filenames (list filenames))) + (let ((config-file nil)) + (while (and filenames (null config-file)) + (setq config-file (run-hook-with-args-until-success + 'flycheck-locate-config-file-functions + (pop filenames) checker))) + (when (and config-file (file-exists-p config-file)) + config-file))) + +(defun flycheck-locate-config-file-by-path (filepath _checker) + "Locate a configuration file by a FILEPATH. + +If FILEPATH is a contains a path separator, expand it against the +default directory and return it if it points to an existing file. +Otherwise return nil. + +_CHECKER is ignored." + ;; If the path is just a plain file name, skip it. + (unless (string= (file-name-nondirectory filepath) filepath) + (let ((file-name (expand-file-name filepath))) + (and (file-exists-p file-name) file-name)))) + +(defun flycheck-locate-config-file-ancestor-directories (filename _checker) + "Locate a configuration FILENAME in ancestor directories. + +If the current buffer has a file name, search FILENAME in the +directory of the current buffer and all ancestors thereof (see +`locate-dominating-file'). If the file is found, return its +absolute path. Otherwise return nil. + +_CHECKER is ignored." + (-when-let* ((basefile (buffer-file-name)) + (directory (locate-dominating-file basefile filename))) + (expand-file-name filename directory))) + +(defun flycheck-locate-config-file-home (filename _checker) + "Locate a configuration FILENAME in the home directory. + +Return the absolute path, if FILENAME exists in the user's home +directory, or nil otherwise." + (let ((path (expand-file-name filename "~"))) + (when (file-exists-p path) + path))) + +(seq-do (apply-partially #'custom-add-frequent-value + 'flycheck-locate-config-file-functions) + '(flycheck-locate-config-file-by-path + flycheck-locate-config-file-ancestor-directories + flycheck-locate-config-file-home)) + +(defun flycheck-register-option-var (var checkers) + "Register an option VAR with CHECKERS. + +VAR is an option symbol, and CHECKERS a syntax checker symbol or +a list thereof. Register VAR with all CHECKERS so that it +appears in the help output." + (when (symbolp checkers) + (setq checkers (list checkers))) + (dolist (checker checkers) + (cl-pushnew var (flycheck-checker-get checker 'option-vars)))) + +;;;###autoload +(defmacro flycheck-def-option-var (symbol init-value checkers docstring + &rest custom-args) + "Define SYMBOL as option variable with INIT-VALUE for CHECKER. + +SYMBOL is declared as customizable variable using `defcustom', to +provide an option for the given syntax CHECKERS (a checker or a +list of checkers). INIT-VALUE is the initial value of the +variable, and DOCSTRING is its docstring. CUSTOM-ARGS are +forwarded to `defcustom'. + +Use this together with the `option', `option-list' and +`option-flag' forms in the `:command' argument to +`flycheck-define-checker'." + (declare (indent 3) + (doc-string 4)) + `(progn + (defcustom ,symbol ,init-value + ,(concat docstring " + +This variable is an option for the following syntax checkers: + +" + (mapconcat (lambda (c) (format " - `%s'" c)) + (if (symbolp checkers) (list checkers) checkers) + "\n")) + :group 'flycheck-options + ,@custom-args) + (flycheck-register-option-var ',symbol ',checkers))) + +(defun flycheck-option-int (value) + "Convert an integral option VALUE to a string. + +If VALUE is nil, return nil. Otherwise return VALUE converted to +a string." + (and value (number-to-string value))) + +(defun flycheck-option-symbol (value) + "Convert a symbol option VALUE to string. + +If VALUE is nil return nil. Otherwise return VALUE converted to +a string." + (and value (symbol-name value))) + +(defun flycheck-option-comma-separated-list (value &optional separator filter) + "Convert VALUE into a list separated by SEPARATOR. + +SEPARATOR is a string to separate items in VALUE, defaulting to +\",\". FILTER is an optional function, which takes a single +argument and returns either a string or nil. + +If VALUE is a list, apply FILTER to each item in VALUE, remove +all nil items, and return a single string of all remaining items +separated by SEPARATOR. + +Otherwise, apply FILTER to VALUE and return the result. +SEPARATOR is ignored in this case." + (let ((filter (or filter #'identity)) + (separator (or separator ","))) + (if (listp value) + (-when-let (value (delq nil (seq-map filter value))) + (string-join value separator)) + (funcall filter value)))) + +(defmacro flycheck-def-args-var (symbol checkers &rest custom-args) + "Define SYMBOL as argument variable for CHECKERS. + +SYMBOL is declared as customizable, risky and buffer-local +variable using `defcustom' to provide an option for arbitrary +arguments for the given syntax CHECKERS (either a single checker +or a list of checkers). CUSTOM-ARGS is forwarded to `defcustom'. + +Use the `eval' form to splice this variable into the +`:command'." + (declare (indent 2)) + `(flycheck-def-option-var ,symbol nil ,checkers + "A list of additional command line arguments. + +The value of this variable is a list of strings with additional +command line arguments." + :risky t + :type '(repeat (string :tag "Argument")) + ,@custom-args)) + + +;;; Command syntax checkers as compile commands +(defun flycheck-checker-pattern-to-error-regexp (pattern) + "Convert PATTERN into an error regexp for compile.el. + +Return a list representing PATTERN, suitable as element in +`compilation-error-regexp-alist'." + (let* ((regexp (car pattern)) + (level (cdr pattern)) + (level-no (flycheck-error-level-compilation-level level))) + `(,regexp 1 (2 . 6) (3 . 7) ,level-no))) + +(defun flycheck-checker-compilation-error-regexp-alist (checker) + "Convert error patterns of CHECKER for use with compile.el. + +Return an alist of all error patterns of CHECKER, suitable for +use with `compilation-error-regexp-alist'." + (seq-map #'flycheck-checker-pattern-to-error-regexp + (flycheck-checker-get checker 'error-patterns))) + +(defun flycheck--substitute-shell-command-argument (arg checker) + "Substitute ARG for CHECKER. + +Like `flycheck-substitute-argument', except for source, +source-inplace, and source-original." + (if (memq arg '(source source-inplace source-original)) + (list buffer-file-name) + (flycheck-substitute-argument arg checker))) + +(defun flycheck--checker-substituted-shell-command-arguments (checker) + "Get the substituted arguments of a CHECKER to run as a shell command. + +Substitute each argument of CHECKER using +`flycheck-substitute-shell-command-argument'." + (apply #'append + (seq-map (lambda (arg) + (flycheck--substitute-shell-command-argument arg checker)) + (flycheck-checker-arguments checker)))) + +(defun flycheck-checker-shell-command (checker) + "Get a shell command for CHECKER. + +Perform substitution in the arguments of CHECKER, but with +`flycheck--substitute-shell-command-argument'. + +Return the command of CHECKER as single string, suitable for +shell execution." + ;; Note: Do NOT use `combine-and-quote-strings' here. Despite it's name it + ;; does not properly quote shell arguments, and actually breaks for special + ;; characters. See https://github.com/flycheck/flycheck/pull/522 + (let* ((args (flycheck--checker-substituted-shell-command-arguments checker)) + (program + (or (flycheck-find-checker-executable checker) + (user-error "Cannot find `%s' using `flycheck-executable-find'" + (flycheck-checker-executable checker)))) + (wrapped (flycheck--wrap-command program args)) + (abs-prog + ;; The executable path returned by `flycheck-command-wrapper-function' + ;; may not be absolute, so expand it here. See URL + ;; `https://github.com/flycheck/flycheck/issues/1461'. + (or (executable-find (car wrapped)) + (user-error "Cannot find `%s' using `executable-find'" + (car wrapped)))) + (command (mapconcat #'shell-quote-argument + (cons abs-prog (cdr wrapped)) " "))) + (if (flycheck-checker-get checker 'standard-input) + ;; If the syntax checker expects the source from standard input add an + ;; appropriate shell redirection + (concat command " < " (shell-quote-argument (buffer-file-name))) + command))) + +(defun flycheck-compile-name (_name) + "Get a name for a Flycheck compilation buffer. + +_NAME is ignored." + (format "*Flycheck %s*" (buffer-file-name))) + +(defun flycheck-compile (checker) + "Run CHECKER via `compile'. + +CHECKER must be a valid syntax checker. Interactively, prompt +for a syntax checker to run. + +Instead of highlighting errors in the buffer, this command pops +up a separate buffer with the entire output of the syntax checker +tool, just like `compile' (\\[compile])." + (interactive + (let ((default (flycheck-get-checker-for-buffer))) + (list (flycheck-read-checker "Run syntax checker as compile command: " + (when (flycheck-checker-get default 'command) + default) + 'command)))) + (unless (flycheck-valid-checker-p checker) + (user-error "%S is not a valid syntax checker" checker)) + (unless (buffer-file-name) + (user-error "Cannot compile a buffer without a backing file")) + (unless (flycheck-may-use-checker checker) + (user-error "Cannot use syntax checker %S in this buffer" checker)) + (unless (flycheck-checker-executable checker) + (user-error "Cannot run checker %S as shell command" checker)) + (save-some-buffers) + (let* ((default-directory (flycheck-compute-working-directory checker)) + (command (flycheck-checker-shell-command checker)) + (buffer (compilation-start command nil #'flycheck-compile-name))) + (with-current-buffer buffer + (setq-local compilation-error-regexp-alist + (flycheck-checker-compilation-error-regexp-alist checker))))) + + +;;; General error parsing for command checkers +(defun flycheck-parse-output (output checker buffer) + "Parse OUTPUT from CHECKER in BUFFER. + +OUTPUT is a string with the output from the checker symbol +CHECKER. BUFFER is the buffer which was checked. + +Return the errors parsed with the error patterns of CHECKER." + (funcall (flycheck-checker-get checker 'error-parser) output checker buffer)) + +(defun flycheck-fix-error-filename (err buffer-files cwd) + "Fix the file name of ERR from BUFFER-FILES. + +Resolves error file names relative to CWD directory. + +Make the file name of ERR absolute. If the absolute file name of +ERR is in BUFFER-FILES, replace it with the value of variable +`buffer-file-name'." + (flycheck-error-with-buffer err + (-when-let (filename (flycheck-error-filename err)) + (when (seq-some (apply-partially #'flycheck-same-files-p + (expand-file-name filename cwd)) + buffer-files) + (setf (flycheck-error-filename err) buffer-file-name) + (when (and buffer-file-name (flycheck-error-message err)) + (setf (flycheck-error-message err) + (replace-regexp-in-string + (regexp-quote filename) buffer-file-name + (flycheck-error-message err) 'fixed-case 'literal)))))) + err) + + +;;; Error parsers for command syntax checkers +(defun flycheck-parse-xml-region (beg end) + "Parse the xml region between BEG and END. + +Wrapper around `xml-parse-region' which transforms the return +value of this function into one compatible to +`libxml-parse-xml-region' by simply returning the first element +from the node list." + (ignore-errors (car (xml-parse-region beg end)))) + +(defun flycheck-parse-xml-region-with-fallback (beg end) + "Parse the xml region between BEG and END. + +Try parsing with libxml first; if that fails, revert to +`flycheck-parse-xml-region'. Failures can be caused by incorrect +XML (see URL `https://github.com/flycheck/flycheck/issues/1298'), +or on Windows by a missing libxml DLL with a libxml-enabled Emacs +\(see URL `https://github.com/flycheck/flycheck/issues/1330')." + ;; FIXME use `libxml-available-p' when it gets implemented. + (or (and (fboundp 'libxml-parse-xml-region) + (libxml-parse-xml-region beg end)) + (flycheck-parse-xml-region beg end))) + +(defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback + "Function used to parse an xml string from a region. + +The default uses libxml if available, and falls back to +`flycheck-parse-xml-region' otherwise.") + +(defun flycheck-parse-xml-string (xml) + "Parse an XML string. + +Return the document tree parsed from XML in the form `(ROOT ATTRS +BODY...)'. ROOT is a symbol identifying the name of the root +element. ATTRS is an alist of the attributes of the root node. +BODY is zero or more body elements, either as strings (in case of +text nodes) or as XML nodes, in the same for as the root node." + (with-temp-buffer + (insert xml) + (funcall flycheck-xml-parser (point-min) (point-max)))) + +(defun flycheck-parse-checkstyle (output checker buffer) + "Parse Checkstyle errors from OUTPUT. + +Parse Checkstyle-like XML output. Use this error parser for +checkers that have an option to output errors in this format. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://checkstyle.sourceforge.net/' for information +about Checkstyle." + (pcase (flycheck-parse-xml-string output) + (`(checkstyle ,_ . ,file-nodes) + (let (errors) + (dolist (node file-nodes) + (pcase node + (`(file ,file-attrs . ,error-nodes) + (dolist (node error-nodes) + (pcase node + (`(error ,error-attrs . ,_) + (let-alist error-attrs + (push (flycheck-error-new-at + (flycheck-string-to-number-safe .line) + (flycheck-string-to-number-safe .column) + (pcase .severity + (`"error" 'error) + (`"warning" 'warning) + (`"info" 'info) + ;; Default to error for unknown .severity + (_ 'error)) + .message + :checker checker :id .source + :buffer buffer + :filename (cdr (assq 'name file-attrs))) + errors)))))))) + (nreverse errors))))) + +(defun flycheck-parse-cppcheck (output checker buffer) + "Parse Cppcheck errors from OUTPUT. + +Parse Cppcheck XML v2 output. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://cppcheck.sourceforge.net/' for more information +about Cppcheck." + (pcase (flycheck-parse-xml-string output) + (`(results ,_ . ,body) + (let (errors) + (dolist (node body) + (pcase node + (`(errors ,_ . ,error-nodes) + (dolist (node error-nodes) + (pcase node + (`(error ,error-attrs . ,loc-nodes) + (let ((id (cdr (assq 'id error-attrs))) + (message (cdr (assq 'verbose error-attrs))) + (level (pcase (cdr (assq 'severity error-attrs)) + (`"error" 'error) + (`"style" 'info) + (`"information" 'info) + (_ 'warning)))) + (dolist (node loc-nodes) + (pcase node + (`(location ,loc-attrs . ,_) + (let-alist loc-attrs + (push (flycheck-error-new-at + (flycheck-string-to-number-safe .line) + nil + level + ;; cppcheck return newline characters as "\012" + (replace-regexp-in-string "\\\\012" "\n" + message) + :id id + :checker checker + :buffer buffer + :filename .file) + errors)))))))))))) + (nreverse errors))))) + +(defun flycheck-parse-phpmd (output checker buffer) + "Parse phpmd errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://phpmd.org/' for more information about phpmd." + (pcase (flycheck-parse-xml-string output) + (`(pmd ,_ . ,body) + (let (errors) + (dolist (node body) + (pcase node + (`(file ,file-attrs . ,violation-nodes) + (let ((filename (cdr (assq 'name file-attrs)))) + (dolist (node violation-nodes) + (pcase node + (`(violation ,vio-attrs ,(and message (pred stringp))) + (let-alist vio-attrs + (push + (flycheck-error-new-at + (flycheck-string-to-number-safe .beginline) + nil + 'warning (string-trim message) + ;; Ignore .endline (phpmd marks giant spans as errors) + ;; :end-line (flycheck-string-to-number-safe .endline) + :id .rule + :checker checker + :buffer buffer + :filename filename) + errors))))))))) + (nreverse errors))))) + +(defun flycheck-parse-reek (output checker buffer) + "Parse Reek warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://github.com/troessner/reek' for more information +about Reek." + (let ((errors nil)) + (dolist (message (car (flycheck-parse-json output))) + (let-alist message + (dolist (line (delete-dups .lines)) + (push + (flycheck-error-new-at + line + nil + 'warning (concat .context " " .message) + :id .smell_type + :checker checker + :buffer buffer + :filename .source) + errors)))) + (nreverse errors))) + +(defun flycheck-parse-go-staticcheck (output checker buffer) + "Parse staticheck warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://staticcheck.io/docs/formatters' for more +information about staticheck." + (let ((errors nil)) + (dolist (msg (flycheck-parse-json output)) + (let-alist msg + (push + (flycheck-error-new-at + .location.line + .location.column + (pcase .severity + (`"error" 'error) + (`"warning" 'warning) + (`"ignored" 'info) + ;; Default to warning for unknown .severity + (_ 'warning)) + .message + :id .code + :checker checker + :buffer buffer + :filename .location.file) + errors))) + (nreverse errors))) + +(defun flycheck-parse-tslint (output checker buffer) + "Parse TSLint errors from JSON OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://palantir.github.io/tslint/' for more information +about TSLint." + (seq-map (lambda (message) + (let-alist message + (flycheck-error-new-at + (+ 1 .startPosition.line) + (+ 1 .startPosition.character) + (pcase .ruleSeverity + ("ERROR" 'error) + ("WARNING" 'warning) + (_ 'warning)) + .failure + :id .ruleName + :checker checker + :buffer buffer + :filename .name + :end-line (+ 1 .endPosition.line) + :end-column (+ 1 .endPosition.character)))) + (car (flycheck-parse-json output)))) + +(defun flycheck-parse-rust-collect-spans (span) + "Return a list of spans contained in a SPAN object." + (let ((spans)) + (let-alist span + ;; With macro expansion errors, some spans will point to phony file names + ;; to indicate an error inside the std rust lib. We skip these spans as + ;; they won't appear in flycheck anyway. + (unless (string= .file_name "") + (push span spans)) + + ;; Macro expansion errors will have a span in the 'expansion' field, so we + ;; recursively collect it. + (if .expansion.span + (append (flycheck-parse-rust-collect-spans .expansion.span) + spans) + spans)))) + +(defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer) + "Turn a rustc DIAGNOSTIC into a `flycheck-error'. + +CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC +and the BUFFER that was checked respectively. + +DIAGNOSTIC should be a parsed JSON object describing a rustc +diagnostic, following the format described there: + +https://github.com/rust-lang/rust/blob/master/src/librustc_errors/json.rs#L154" + (let ((error-message) + (error-level) + (error-code) + (primary-filename) + (primary-line) + (primary-column) + (primary-end-line) + (primary-end-column) + (group (make-symbol "group")) + (spans) + (children) + (errors)) + ;; The diagnostic format is described in the link above. The gist of it is + ;; that a diagnostic can have several causes in the source text; these + ;; causes are represented by spans. The diagnostic has a message and a + ;; level (error, warning), while the spans have a filename, line, column, + ;; and an optional label. The primary span points to the root cause of the + ;; error in the source text, while non-primary spans point to related + ;; causes. Spans may have an 'expansion' field for macro expansion errors; + ;; these expansion fields will contain another span (and so on). In + ;; addition, a diagnostic can also have children diagnostics that are used + ;; to provide additional information through their message field, but do not + ;; seem to contain any spans (yet). + ;; + ;; We first gather spans in order to turn every span into a flycheck error + ;; object, that we collect into the `errors' list. + + ;; Nested `let-alist' cause compilation warnings, hence we `setq' all + ;; these values here first to avoid nesting. + (let-alist diagnostic + (setq error-message .message + error-level (pcase .level + (`"error" 'error) + (`"warning" 'warning) + (`"note" 'info) + (_ 'error)) + ;; The 'code' field of the diagnostic contains the actual error + ;; code and an optional explanation that we ignore + error-code .code.code + ;; Collect all spans recursively + spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans) + children .children)) + + ;; Turn each span into a flycheck error + (dolist (span spans) + (let-alist span + ;; Children may not have filename/line/column information, so we use + ;; those from the primary span + (when .is_primary + (setq primary-filename .file_name + primary-line .line_start + primary-column .column_start + primary-end-line .line_end + primary-end-column .column_end)) + (push + (flycheck-error-new-at + .line_start + .column_start + ;; Non-primary spans are used for notes + (if .is_primary error-level 'info) + (if .is_primary + ;; Primary spans may have labels with additional information + (concat error-message (when .label + (format " (%s)" .label))) + ;; If the label is empty, fallback on the error message, + ;; otherwise we won't be able to display anything + (or .label error-message)) + :id error-code + :checker checker + :buffer buffer + :filename .file_name + :group group + :end-line .line_end + :end-column .column_end) + errors))) + + ;; Then we turn children messages into flycheck errors pointing to the + ;; location of the primary span. + (dolist (child children) + (let ((message (let-alist child .message))) + (let-alist (car (let-alist child .spans)) + (push + (flycheck-error-new-at + ;; Use the line/column from the first span if there is one, or + ;; fallback to the line/column information from the primary span of + ;; the diagnostic. + (or .line_start primary-line) + (or .column_start primary-column) + 'info + ;; Messages from `cargo clippy' may suggest replacement code. In + ;; these cases, the `message' field itself is an unhelpful `try' or + ;; `change this to'. We add the `suggested_replacement' field in + ;; these cases. + (if .suggested_replacement + (format "%s: `%s`" message .suggested_replacement) + message) + :id error-code + :checker checker + :buffer buffer + :filename primary-filename + :group group + :end-line (or .line_end primary-end-line) + :end-column (or .column_end primary-end-column)) + errors)))) + + ;; If there are no spans, the error is not associated with a specific + ;; file but with the project as a whole. We still need to report it to + ;; the user by emitting a corresponding flycheck-error object. + ;; Check whether the code is non-nil because Rust≥1.44 includes the + ;; warning count upon completion. + (when (and error-code (not spans)) + (push (flycheck-error-new-at + ;; We have no specific position to attach the error to, so + ;; let's use the top of the file. + 1 1 + error-level + error-message + :id error-code + :checker checker + :buffer buffer + :group group) + errors)) + (nreverse errors))) + +(defconst flycheck--json-parser + (if (and (functionp 'json-parse-buffer) + ;; json-parse-buffer only supports keyword arguments in Emacs 27+ + (>= emacs-major-version 27)) + (lambda () + (json-parse-buffer + :object-type 'alist :array-type 'list + :null-object nil :false-object nil)) + #'json-read) + "Function to use to parse JSON strings.") + +(defun flycheck-parse-json (output) + "Return parsed JSON data from OUTPUT. + +OUTPUT is a string that contains JSON data. Each line of OUTPUT +may be either plain text, a JSON array (starting with `['), or a +JSON object (starting with `{'). + +This function ignores the plain text lines, parses the JSON +lines, and returns the parsed JSON lines in a list." + (let ((objects nil) + (json-array-type 'list) + (json-false nil)) + (with-temp-buffer + (insert output) + (goto-char (point-min)) + (while (not (eobp)) + (when (memq (char-after) '(?\{ ?\[)) + (push (funcall flycheck--json-parser) objects)) + (forward-line))) + (nreverse objects))) + +(defun flycheck-parse-rustc (output checker buffer) + "Parse rustc errors from OUTPUT and return a list of `flycheck-error'. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +The expected format for OUTPUT is a mix of plain text lines and +JSON lines. This function ignores the plain text lines and +parses only JSON lines. Each JSON line is expected to be a JSON +object that corresponds to a diagnostic from the compiler. The +expected diagnostic format is described there: + +https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139" + (seq-mapcat (lambda (msg) + (flycheck-parse-rustc-diagnostic msg checker buffer)) + (flycheck-parse-json output))) + +(defun flycheck-parse-cargo-rustc (output checker buffer) + "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +The expected format for OUTPUT is a mix of plain text lines and +JSON lines. This function ignores the plain text lines and +parses only JSON lines. Each JSON line is expected to be a JSON +object that represents a message from Cargo. The format of +messages emitted by Cargo is described in cargo's +machine_message.rs at URL `https://git.io/vh24R'." + (let ((errors)) + (dolist (msg (flycheck-parse-json output)) + (let-alist msg + ;; Errors and warnings from rustc are wrapped by cargo, so we filter and + ;; unwrap them, and delegate the actual construction of `flycheck-error' + ;; objects to `flycheck-parse-rustc-diagnostic'. + ;; We put the error record with nil code since flycheck regards + ;; the case of nonzero return code without any error report + ;; as abnormal result. + (when (string= .reason "compiler-message") + (push (flycheck-parse-rustc-diagnostic .message checker buffer) + errors)))) + (apply #'nconc errors))) + +;; Some checkers output ANSI terminal colors, which don't match up +;; with :error-patterns, so we strip those color codes from the output +;; here before passing it along to the default behavior. This is +;; originally only used in the rebar3 checker, but the systemd checker +;; now also makes use of it. +;; +;; The relevant discussion can be found at +;; https://github.com/flycheck/flycheck/pull/1144 +(defun flycheck-parse-with-patterns-without-color (output checker buffer) + "Strip color codes from OUTPUT before passing it to the default behavior. + +CHECKER and BUFFER are passed along as well." + (flycheck-parse-with-patterns + (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output)) + checker buffer)) + + +;;; Error parsing with regular expressions +(defun flycheck-get-regexp (patterns) + "Create a single regular expression from PATTERNS." + (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns)) + 'no-group)) + +(defun flycheck-tokenize-output-with-patterns (output patterns) + "Tokenize OUTPUT with PATTERNS. + +Split the output into error tokens, using all regular expressions +from the error PATTERNS. An error token is simply a string +containing a single error from OUTPUT. Such a token can then be +parsed into a structured error by applying the PATTERNS again, +see `flycheck-parse-errors-with-patterns'. + +Return a list of error tokens." + (let ((regexp (flycheck-get-regexp patterns)) + (last-match 0) + errors) + (while (string-match regexp output last-match) + (push (match-string 0 output) errors) + (setq last-match (match-end 0))) + (reverse errors))) + +(defun flycheck-try-parse-error-with-pattern (err pattern checker) + "Try to parse a single ERR with a PATTERN for CHECKER. + +Return the parsed error if PATTERN matched ERR, or nil +otherwise. + +`end-line' defaults to the value of `line' when `end-column' is +set, since checkers often omit redundant end lines (as in +::-)." + (let ((regexp (car pattern)) + (level (cdr pattern))) + (when (string-match regexp err) + (let ((filename (match-string 1 err)) + (line (flycheck-string-to-number-safe (match-string 2 err))) + (column (flycheck-string-to-number-safe (match-string 3 err))) + (message (match-string 4 err)) + (id (match-string 5 err)) + (end-line (flycheck-string-to-number-safe (match-string 6 err))) + (end-column (flycheck-string-to-number-safe (match-string 7 err)))) + (flycheck-error-new-at + line + column + level + (unless (string-empty-p message) message) + :id (unless (string-empty-p id) id) + :checker checker + :filename (if (or (null filename) (string-empty-p filename)) + (buffer-file-name) + filename) + :end-line (or end-line (and end-column line)) + :end-column end-column))))) + +(defun flycheck-parse-error-with-patterns (err patterns checker) + "Parse a single ERR with error PATTERNS for CHECKER. + +Apply each pattern in PATTERNS to ERR, in the given order, and +return the first parsed error." + ;; Try to parse patterns in the order of declaration to make sure that the + ;; first match wins. + (let (parsed-error) + (while (and patterns + (not (setq parsed-error + (flycheck-try-parse-error-with-pattern + err (car patterns) checker)))) + (setq patterns (cdr patterns))) + parsed-error)) + +(defun flycheck-parse-with-patterns (output checker buffer) + "Parse OUTPUT from CHECKER with error patterns. + +Uses the error patterns of CHECKER to tokenize the output and +tries to parse each error token with all patterns, in the order +of declaration. Hence an error is never matched twice by two +different patterns. The pattern declared first always wins. + +_BUFFER is ignored. + +Return a list of parsed errors and warnings (as `flycheck-error' +objects)." + (with-current-buffer buffer + (let ((patterns (flycheck-checker-get checker 'error-patterns))) + (seq-map (lambda (err) + (flycheck-parse-error-with-patterns err patterns checker)) + (flycheck-tokenize-output-with-patterns output patterns))))) + + +;;; Convenience definition of command-syntax checkers + +;; This macro is autoloaded to prevent `with-eval-after-load' from expanding its +;; arguments. See https://github.com/flycheck/flycheck/issues/1398. +;;;###autoload +(defmacro flycheck-define-checker (symbol docstring &rest properties) + "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES. + +Like `flycheck-define-command-checker', but PROPERTIES must not +be quoted. Also, implicitly define the executable variable for +SYMBOL with `flycheck-def-executable-var'." + (declare (indent 1) + (doc-string 2)) + (let ((command (plist-get properties :command)) + (parser (plist-get properties :error-parser)) + (filter (plist-get properties :error-filter)) + (explainer (plist-get properties :error-explainer)) + (predicate (plist-get properties :predicate)) + (enabled-fn (plist-get properties :enabled)) + (verify-fn (plist-get properties :verify))) + + `(progn + (flycheck-def-executable-var ,symbol ,(car command)) + + (flycheck-define-command-checker ',symbol + ,docstring + :command ',command + ,@(when parser + `(:error-parser #',parser)) + :error-patterns ',(plist-get properties :error-patterns) + ,@(when filter + `(:error-filter #',filter)) + ,@(when explainer + `(:error-explainer #',explainer)) + :modes ',(plist-get properties :modes) + ,@(when predicate + `(:predicate #',predicate)) + :next-checkers ',(plist-get properties :next-checkers) + ,@(when enabled-fn + `(:enabled #',enabled-fn)) + ,@(when verify-fn + `(:verify #',verify-fn)) + :standard-input ',(plist-get properties :standard-input) + :working-directory ',(plist-get properties :working-directory))))) + + +;;; Built-in checkers +(flycheck-def-args-var flycheck-gnat-args ada-gnat + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat + "A list of include directories for GNAT. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of gcc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat + "The language standard to use in GNAT. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, pass +the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gnat-warnings + '("wa") ada-gnat + "A list of additional Ada warnings to enable in GNAT. + +The value of this variable is a list of strings, where each +string is the name of a warning category to enable. By default, +most optional warnings are recommended, as in `-gnata'. + +Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for +more information about GNAT warnings." + :type '(repeat :tag "Warnings" (string :tag "Warning name")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker ada-gnat + "An Ada syntax checker using GNAT. + +Uses the GNAT compiler from GCC. See URL +`https://www.adacore.com/community/'." + :command ("gnatmake" + "-c" ; Just compile, don't bind + "-f" ; Force re-compilation + "-u" ; Compile the main file only + "-gnatf" ; Full error information + "-gnatef" ; Full source file name + "-D" temporary-directory + (option-list "-gnat" flycheck-gnat-warnings concat) + (option-list "-I" flycheck-gnat-include-path concat) + (option "-gnat" flycheck-gnat-language-standard concat) + (eval flycheck-gnat-args) + source) + :error-patterns + ((error line-start + (message "In file included from") " " (file-name) ":" line ":" + column ":" + line-end) + (info line-start (file-name) ":" line ":" column + ": note: " (message) line-end) + (warning line-start (file-name) ":" line ":" column + ": warning: " (message) line-end) + ;; no specific error prefix in Ada + (error line-start (file-name) ":" line ":" column + ": " (message) line-end)) + :modes ada-mode) + +(flycheck-define-checker asciidoc + "A AsciiDoc syntax checker using the AsciiDoc compiler. + +See URL `http://www.methods.co.nz/asciidoc'." + :command ("asciidoc" "-o" null-device "-") + :standard-input t + :error-patterns + ((error line-start + "asciidoc: ERROR: : Line " line ": " (message) + line-end) + (warning line-start + "asciidoc: WARNING: : Line " line ": " (message) + line-end) + (info line-start + "asciidoc: DEPRECATED: : Line " line ": " (message) + line-end)) + :modes adoc-mode) + +(flycheck-define-checker asciidoctor + "An AsciiDoc syntax checker using the Asciidoctor compiler. + +See URL `http://asciidoctor.org'." + :command ("asciidoctor" "-o" null-device "-") + :standard-input t + :error-patterns + ((error line-start + "asciidoctor: ERROR: : Line " line ": " (message) + line-end) + (warning line-start + "asciidoctor: WARNING: : Line " line ": " (message) + line-end)) + :modes adoc-mode) + +(defun flycheck-awk-gawk-fix-message (err) + "Remove the repeated file-name/line from the error message of ERR." + (setf (flycheck-error-message err) + (replace-regexp-in-string + (rx line-start + (group (zero-or-more (any " " "\t"))) + (group (zero-or-more nonl) "\n") + (backref 1)) + "\\2" + (replace-regexp-in-string + (rx "\ngawk: " (zero-or-more (not (any " "))) ":") + "\n" + (flycheck-error-message err)))) + err) + +(defun flycheck-awk-gawk-error-filter (errors) + "Remove repeated file-name/line from ERRORS." + (seq-do #'flycheck-awk-gawk-fix-message errors) + errors) + +(flycheck-define-checker awk-gawk + "GNU awk's built-in --lint checker." + :command ("gawk" + ;; Avoid code execution. See https://github.com/w0rp/ale/pull/1411 + "--source" "'BEGIN{exit} END{exit 1}'" + "-f" source + "--lint" + "/dev/null") + :standard-input nil + :error-patterns + ((warning line-start + "gawk: " + (file-name) ":" line ":" (optional column ":") + (message (one-or-more not-newline) + (optional "\n" + (one-or-more not-newline) + " ^ " + (one-or-more not-newline))) + line-end)) + :error-filter flycheck-awk-gawk-error-filter + :modes awk-mode) + +(flycheck-define-checker bazel-buildifier + "An Bazel checker using the buildifier. + +See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'." + :command ("buildifier" "-lint=warn") + :standard-input t + :error-patterns + ((error line-start + ":" line ":" column ": " (message) + line-end) + (warning line-start + ":" line ": " (id (one-or-more (in word "-"))) ": " (message) + line-end)) + :modes bazel-mode) + +(flycheck-def-args-var flycheck-clang-args c/c++-clang + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang + "Enable blocks in Clang. + +When non-nil, enable blocks in Clang with `-fblocks'. See URL +`http://clang.llvm.org/docs/BlockLanguageSpec.html' for more +information about blocks." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang + "Additional preprocessor definitions for Clang. + +The value of this variable is a list of strings, where each +string is an additional definition to pass to Clang, via the `-D' +option." + :type '(repeat (string :tag "Definition")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang + "A list of include directories for Clang. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of Clang. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.14")) + +(flycheck-def-option-var flycheck-clang-includes nil c/c++-clang + "A list of additional include files for Clang. + +The value of this variable is a list of strings, where each +string is a file to include before syntax checking. Relative +paths are relative to the file being checked." + :type '(repeat (file :tag "Include file")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang + "The language standard to use in Clang. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.15")) +(make-variable-buffer-local 'flycheck-clang-language-standard) + +(flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang + "Whether to enable Microsoft extensions to C/C++ in Clang. + +When non-nil, enable Microsoft extensions to C/C++ via +`-fms-extensions'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang + "Whether to disable exceptions in Clang. + +When non-nil, disable exceptions for syntax checks, via +`-fno-exceptions'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang + "Whether to disable RTTI in Clang. + +When non-nil, disable RTTI for syntax checks, via `-fno-rtti'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang + "Whether to warn about language extensions in Clang. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang + "Whether to error on language extensions in Clang. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic-errors'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang + "The standard library to use for Clang. + +The value of this variable is the name of a standard library as +string, or nil to use the default standard library. + +Refer to the Clang manual at URL +`http://clang.llvm.org/docs/UsersManual.html' for more +information about the standard library." + :type '(choice (const :tag "Default standard library" nil) + (const "libc++") + (const :tag "GNU libstdc++" "libstdc++") + (string :tag "Library name")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang + "A list of additional warnings to enable in Clang. + +The value of this variable is a list of strings, where each string +is the name of a warning category to enable. By default, all +recommended warnings and some extra warnings are enabled (as by +`-Wall' and `-Wextra' respectively). + +Refer to the Clang manual at URL +`http://clang.llvm.org/docs/UsersManual.html' for more +information about warnings." + :type '(choice (const :tag "No additional warnings" nil) + (repeat :tag "Additional warnings" + (string :tag "Warning name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.14")) + +(defun flycheck-c/c++-quoted-include-directory () + "Get the directory for quoted includes. + +C/C++ compilers typically look up includes with quotation marks +in the directory of the file being compiled. However, since +Flycheck uses temporary copies for syntax checking, it needs to +explicitly determine the directory for quoted includes. + +This function determines the directory by looking at function +`buffer-file-name', or if that is nil, at `default-directory'." + (-if-let (fn (buffer-file-name)) + (file-name-directory fn) + ;; If the buffer has no file name, fall back to its default directory + default-directory)) + +(flycheck-define-checker c/c++-clang + "A C/C++ syntax checker using Clang. + +See URL `http://clang.llvm.org/'." + :command ("clang" + "-fsyntax-only" + "-fno-color-diagnostics" ; Do not include color codes in output + "-fno-caret-diagnostics" ; Do not visually indicate the source + ; location + "-fno-diagnostics-show-option" ; Do not show the corresponding + ; warning group + "-iquote" (eval (flycheck-c/c++-quoted-include-directory)) + (option "-std=" flycheck-clang-language-standard concat) + (option-flag "-pedantic" flycheck-clang-pedantic) + (option-flag "-pedantic-errors" flycheck-clang-pedantic-errors) + (option "-stdlib=" flycheck-clang-standard-library concat) + (option-flag "-fms-extensions" flycheck-clang-ms-extensions) + (option-flag "-fno-exceptions" flycheck-clang-no-exceptions) + (option-flag "-fno-rtti" flycheck-clang-no-rtti) + (option-flag "-fblocks" flycheck-clang-blocks) + (option-list "-include" flycheck-clang-includes) + (option-list "-W" flycheck-clang-warnings concat) + (option-list "-D" flycheck-clang-definitions concat) + (option-list "-I" flycheck-clang-include-path) + (eval flycheck-clang-args) + "-x" (eval + (pcase major-mode + (`c++-mode "c++") + (`c-mode "c"))) + ;; Read from standard input + "-") + :standard-input t + :error-patterns + ((info line-start (or "" (file-name)) ":" line ":" column + ": note: " (optional (message)) line-end) + (warning line-start (or "" (file-name)) ":" line ":" column + ": warning: " (optional (message)) line-end) + (error line-start (or "" (file-name)) ":" line ":" column + ": " (or "fatal error" "error") ": " (optional (message)) line-end)) + :error-filter + (lambda (errors) + (let ((errors (flycheck-sanitize-errors errors))) + (dolist (err errors) + ;; Clang will output empty messages for #error/#warning pragmas without + ;; messages. We fill these empty errors with a dummy message to get + ;; them past our error filtering + (setf (flycheck-error-message err) + (or (flycheck-error-message err) "no message"))) + errors)) + :modes (c-mode c++-mode) + :next-checkers ((warning . c/c++-cppcheck))) + +(flycheck-def-args-var flycheck-gcc-args c/c++-gcc + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-gcc-definitions nil c/c++-gcc + "Additional preprocessor definitions for GCC. + +The value of this variable is a list of strings, where each +string is an additional definition to pass to GCC, via the `-D' +option." + :type '(repeat (string :tag "Definition")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-include-path nil c/c++-gcc + "A list of include directories for GCC. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of gcc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-includes nil c/c++-gcc + "A list of additional include files for GCC. + +The value of this variable is a list of strings, where each +string is a file to include before syntax checking. Relative +paths are relative to the file being checked." + :type '(repeat (file :tag "Include file")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-language-standard nil c/c++-gcc + "The language standard to use in GCC. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.20")) +(make-variable-buffer-local 'flycheck-gcc-language-standard) + +(flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc + "Whether to disable exceptions in GCC. + +When non-nil, disable exceptions for syntax checks, via +`-fno-exceptions'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc + "Whether to disable RTTI in GCC. + +When non-nil, disable RTTI for syntax checks, via `-fno-rtti'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc + "Whether to enable OpenMP in GCC. + +When non-nil, enable OpenMP for syntax checkers, via +`-fopenmp'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.21")) + +(flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc + "Whether to warn about language extensions in GCC. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc + "Whether to error on language extensions in GCC. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic-errors'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc + "A list of additional warnings to enable in GCC. + +The value of this variable is a list of strings, where each string +is the name of a warning category to enable. By default, all +recommended warnings and some extra warnings are enabled (as by +`-Wall' and `-Wextra' respectively). + +Refer to the gcc manual at URL +`https://gcc.gnu.org/onlinedocs/gcc/' for more information about +warnings." + :type '(choice (const :tag "No additional warnings" nil) + (repeat :tag "Additional warnings" + (string :tag "Warning name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker c/c++-gcc + "A C/C++ syntax checker using GCC. + +Requires GCC 4.4 or newer. See URL `https://gcc.gnu.org/'." + :command ("gcc" + "-fshow-column" + "-iquote" (eval (flycheck-c/c++-quoted-include-directory)) + (option "-std=" flycheck-gcc-language-standard concat) + (option-flag "-pedantic" flycheck-gcc-pedantic) + (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors) + (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions) + (option-flag "-fno-rtti" flycheck-gcc-no-rtti) + (option-flag "-fopenmp" flycheck-gcc-openmp) + (option-list "-include" flycheck-gcc-includes) + (option-list "-W" flycheck-gcc-warnings concat) + (option-list "-D" flycheck-gcc-definitions concat) + (option-list "-I" flycheck-gcc-include-path) + (eval flycheck-gcc-args) + "-x" (eval + (pcase major-mode + (`c++-mode "c++") + (`c-mode "c"))) + ;; GCC performs full checking only when actually compiling, so + ;; `-fsyntax-only' is not enough. Just let it generate assembly + ;; code. + "-S" "-o" null-device + ;; Read from standard input + "-") + :standard-input t + :error-patterns + ((info line-start (or "" (file-name)) + ":" line (optional ":" column) + ": note: " (message) line-end) + (warning line-start (or "" (file-name)) + ":" line (optional ":" column) + ": warning: " (message (one-or-more (not (any "\n[")))) + (optional "[" (id (one-or-more not-newline)) "]") line-end) + (error line-start (or "" (file-name)) + ":" line (optional ":" column) + ": " (or "fatal error" "error") ": " (message) line-end)) + :modes (c-mode c++-mode) + :next-checkers ((warning . c/c++-cppcheck))) + +(flycheck-def-option-var flycheck-cppcheck-checks '("style") c/c++-cppcheck + "Enabled checks for Cppcheck. + +The value of this variable is a list of strings, where each +string is the name of an additional check to enable. By default, +all coding style checks are enabled. + +See section \"Enable message\" in the Cppcheck manual at URL +`http://cppcheck.sourceforge.net/manual.pdf', and the +documentation of the `--enable' option for more information, +including a list of supported checks." + :type '(repeat :tag "Additional checks" + (string :tag "Check name")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.14")) + +(flycheck-def-option-var flycheck-cppcheck-standards nil c/c++-cppcheck + "The standards to use in cppcheck. + +The value of this variable is either a list of strings denoting +the standards to use, or nil to pass nothing to cppcheck. When +non-nil, pass the standards via one or more `--std=' options." + :type '(choice (const :tag "Default" nil) + (repeat :tag "Custom standards" + (string :tag "Standard name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "28")) +(make-variable-buffer-local 'flycheck-cppcheck-standards) + +(flycheck-def-option-var flycheck-cppcheck-suppressions-file nil c/c++-cppcheck + "The suppressions file to use in cppcheck. + +The value of this variable is a file with the suppressions to +use, or nil to pass nothing to cppcheck. When non-nil, pass the +suppressions file via the `--suppressions-list=' option." + :type '(choice (const :tag "Default" nil) + (file :tag "Suppressions file")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-cppcheck-suppressions-file) + +(flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck + "The suppressions to use in cppcheck. + +The value of this variable is either a list of strings denoting +the suppressions to use, or nil to pass nothing to cppcheck. +When non-nil, pass the suppressions via one or more `--suppress=' +options." + :type '(choice (const :tag "Default" nil) + (repeat :tag "Additional suppressions" + (string :tag "Suppression"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "28")) + +(flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck + "Whether to enable Cppcheck inconclusive checks. + +When non-nil, enable Cppcheck inconclusive checks. This allows Cppcheck to +report warnings it's not certain of, but it may result in false positives. + +This will have no effect when using Cppcheck 1.53 and older." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.19")) + +(flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck + "A list of include directories for cppcheck. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of cppcheck. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker c/c++-cppcheck + "A C/C++ checker using cppcheck. + +See URL `http://cppcheck.sourceforge.net/'." + :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr" + (option "--enable=" flycheck-cppcheck-checks concat + flycheck-option-comma-separated-list) + (option-flag "--inconclusive" flycheck-cppcheck-inconclusive) + (option-list "-I" flycheck-cppcheck-include-path) + (option-list "--std=" flycheck-cppcheck-standards concat) + (option-list "--suppress=" flycheck-cppcheck-suppressions concat) + (option "--suppressions-list=" + flycheck-cppcheck-suppressions-file concat) + "-x" (eval + (pcase major-mode + (`c++-mode "c++") + (`c-mode "c"))) + source) + :error-parser flycheck-parse-cppcheck + :modes (c-mode c++-mode)) + +(flycheck-define-checker cfengine + "A CFEngine syntax checker using cf-promises. + +See URL `https://cfengine.com/'." + :command ("cf-promises" "-Wall" "-f" + ;; We must stay in the same directory to resolve @include + source-inplace) + :error-patterns + ((warning line-start (file-name) ":" line ":" column + ": warning: " (message) line-end) + (error line-start (file-name) ":" line ":" column + ": error: " (message) line-end)) + :modes (cfengine-mode cfengine3-mode)) + +(flycheck-def-option-var flycheck-foodcritic-tags nil chef-foodcritic + "A list of tags to select for Foodcritic. + +The value of this variable is a list of strings where each string +is a tag expression describing Foodcritic rules to enable or +disable, via the `--tags' option. To disable a tag, prefix it +with `~'." + :type '(repeat :tag "Tags" (string :tag "Tag expression")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.23")) + +(flycheck-define-checker chef-foodcritic + "A Chef cookbooks syntax checker using Foodcritic. + +See URL `http://www.foodcritic.io'." + ;; Use `source-inplace' to allow resource discovery with relative paths. + ;; foodcritic interprets these as relative to the source file, so we need to + ;; stay within the source tree. See + ;; https://github.com/flycheck/flycheck/pull/556 + :command ("foodcritic" + (option-list "--tags" flycheck-foodcritic-tags) + source-inplace) + :error-patterns + ((error line-start (id (one-or-more alnum)) ": " + (message) ": " (file-name) ":" line line-end)) + :modes (enh-ruby-mode ruby-mode) + :predicate + (lambda () + (let ((parent-dir (file-name-directory + (directory-file-name + (expand-file-name default-directory))))) + (or + ;; Chef CookBook + ;; http://docs.opscode.com/chef/knife.html#id38 + (locate-dominating-file parent-dir "recipes") + ;; Knife Solo + ;; http://matschaffer.github.io/knife-solo/#label-Init+command + (locate-dominating-file parent-dir "cookbooks"))))) + +(flycheck-define-checker coffee + "A CoffeeScript syntax checker using coffee. + +See URL `https://coffeescript.org/'." + ;; --print suppresses generation of compiled .js files + :command ("coffee" "--compile" "--print" "--stdio") + :standard-input t + :error-patterns + ((error line-start "[stdin]:" line ":" column + ": error: " (message) line-end)) + :modes coffee-mode + :next-checkers ((warning . coffee-coffeelint))) + +(flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint + ".coffeelint.json") + +(flycheck-define-checker coffee-coffeelint + "A CoffeeScript style checker using coffeelint. + +See URL `http://www.coffeelint.org/'." + :command + ("coffeelint" + (config-file "--file" flycheck-coffeelintrc) + "--stdin" "--reporter" "checkstyle") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter (lambda (errors) + (flycheck-remove-error-file-names + "stdin" (flycheck-remove-error-ids + (flycheck-sanitize-errors errors)))) + :modes coffee-mode) + +(defun flycheck-coq-error-filter (errors) + "Sanitize Coq ERRORS and compute end-lines and end-columns." + (flycheck-increment-error-columns errors) + (dolist (err errors) + (setf (flycheck-error-message err) + (replace-regexp-in-string (rx (1+ (syntax whitespace)) line-end) + "" (flycheck-error-message err) + 'fixedcase 'literal)) + (-when-let* ((end-col (flycheck-error-end-column err))) + ;; Coq reports an offset (potentially past eol), not an end column + (let* ((line (flycheck-error-line err)) + (end-lc (save-excursion + (flycheck-goto-line line) + (goto-char (+ (point) (1- end-col))) + (flycheck-line-column-at-point)))) + (setf (flycheck-error-end-line err) (car end-lc)) + (setf (flycheck-error-end-column err) (cdr end-lc))))) + (flycheck-sanitize-errors errors)) + +(flycheck-define-checker coq + "A Coq syntax checker using the Coq compiler. + +See URL `https://coq.inria.fr/'." + ;; We use coqtop in batch mode, because coqc is picky about file names. + :command ("coqtop" "-batch" "-load-vernac-source" source) + :error-patterns + ((error line-start "File \"" (file-name) "\", line " line + ", characters " column "-" end-column ":\n" + (or "Syntax error:" "Error:") + ;; Most Coq error messages span multiple lines, and end with a dot. + ;; There are simple one-line messages, too, though. + (message (or (and (one-or-more (or not-newline "\n")) ".") + (one-or-more not-newline))) + line-end)) + :error-filter flycheck-coq-error-filter + :modes coq-mode) + +(flycheck-define-checker css-csslint + "A CSS syntax and style checker using csslint. + +See URL `https://github.com/CSSLint/csslint'." + :command ("csslint" "--format=checkstyle-xml" source) + :error-parser flycheck-parse-checkstyle + :error-filter flycheck-dequalify-error-ids + :modes css-mode) + +(defconst flycheck-stylelint-args '("--formatter" "json") + "Common arguments to stylelint invocations.") + +(flycheck-def-config-file-var flycheck-stylelintrc + (css-stylelint scss-stylelint less-stylelint) nil) + +(flycheck-def-option-var flycheck-stylelint-quiet + nil (css-stylelint scss-stylelint less-stylelint) + "Whether to run stylelint in quiet mode. + +When non-nil, enable quiet mode, via `--quiet'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . 26)) + +(defconst flycheck-stylelint-error-re + (flycheck-rx-to-string + '(: line-start (id (one-or-more word)) ": " (message) line-end))) + +(defun flycheck-parse-stylelint (output checker buffer) + "Parse stylelint errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +The CHECKER usually returns the errors as JSON. + +If the CHECKER throws an Error it returns an Error message with a stacktrace." + (condition-case nil + (flycheck-parse-stylelint-json output checker buffer) + + ;; The output could not be parsed as JSON + (json-error + + ;; Extract a flycheck error from the output (with a regular expression) + ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id + (when (string-match flycheck-stylelint-error-re output) + (list (flycheck-error-new-at + 1 nil 'error + (match-string 4 output) + :id (match-string 5 output) + :checker checker + :buffer buffer + :filename (buffer-file-name buffer))))))) + +(defun flycheck-parse-stylelint-json (output checker buffer) + "Parse stylelint JSON errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://stylelint.io/developer-guide/formatters/' for information +about the JSON format of stylelint." + (let ((json-object-type 'plist)) + + ;; stylelint returns a vector of result objects + ;; Since we only passed one file, the first element is enough + (let* ((stylelint-output (elt (json-read-from-string output) 0)) + (filename (buffer-file-name buffer)) + + ;; Turn all deprecations into warnings + (deprecations + (mapcar (lambda (d) + (flycheck-error-new-at + 1 nil 'warning + (plist-get d :text) + :id "Deprecation Warning" + :checker checker + :buffer buffer + :filename filename)) + (plist-get stylelint-output :deprecations))) + + ;; Turn all invalid options into errors + (invalid-options + (mapcar (lambda (io) + (flycheck-error-new-at + 1 nil 'error + (plist-get io :text) + :id "Invalid Option" + :checker checker + :buffer buffer + :filename filename)) + (plist-get stylelint-output :invalidOptionWarnings))) + + ;; Read all linting warnings + (warnings + (mapcar (lambda (w) + (flycheck-error-new-at + (plist-get w :line) (plist-get w :column) + (pcase (plist-get w :severity) + (`"error" 'error) + (`"warning" 'warning) + ;; Default to info for unknown .severity + (_ 'info)) + (plist-get w :text) + :id (plist-get w :rule) + :checker checker + :buffer buffer + :filename filename)) + (plist-get stylelint-output :warnings)))) + + ;; Return the combined errors (deprecations, invalid options, warnings) + (append deprecations invalid-options warnings)))) + +(flycheck-define-checker css-stylelint + "A CSS syntax and style checker using stylelint. + +See URL `http://stylelint.io/'." + :command ("stylelint" + (eval flycheck-stylelint-args) + (option-flag "--quiet" flycheck-stylelint-quiet) + (config-file "--config" flycheck-stylelintrc) + "--stdin-filename" (eval (or (buffer-file-name) "style.css"))) + :standard-input t + :error-parser flycheck-parse-stylelint + :predicate flycheck-buffer-nonempty-p + :modes (css-mode)) + +(flycheck-def-option-var flycheck-cuda-language-standard nil cuda-nvcc + "Our CUDA Language Standard." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-cuda-language-standard) + +(flycheck-def-option-var flycheck-cuda-includes nil cuda-nvcc + "Our include directories to pass to nvcc." + :type '(repeat (file :tag "Include file")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-cuda-definitions nil cuda-nvcc + "Additional preprocessor definitions for nvcc. +A list of strings to pass to cuda, a la flycheck-clang" + :type '(repeat (string :tag "Definitions")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-cuda-include-path nil cuda-nvcc + "A list of include directories for nvcc." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker cuda-nvcc + "A CUDA C/C++ syntax checker using nvcc. + +See URL `https://developer.nvidia.com/cuda-llvm-compiler'." + :command ("nvcc" + "-c" ;; Compile Only + "--output-file" "/dev/null" ;; avoid creating output .o + "--x=cu" ;; explicitly specify it's a CUDA language file + (option "-std=" flycheck-cuda-language-standard concat) + (option-list "-include" flycheck-cuda-includes) + (option-list "-D" flycheck-cuda-definitions concat) + (option-list "-I" flycheck-cuda-include-path) + source) + :error-patterns + ((error line-start + (message "In file included from") + " " (or "" (file-name)) + ":" line ":" line-end) + (error line-start (or "" (file-name)) + "(" line "): error: " (message) line-end) + (error line-start (or "" (file-name)) + ":" line ":" column + ": fatal error: " (optional (message)) line-end) + (warning line-start (or "" (file-name)) + "(" line "): warning: " (message) line-end)) + :modes cuda-mode) + + +(flycheck-def-option-var flycheck-cwl-schema-path nil cwl + "A path for the schema file for Common Workflow Language. + +The value of this variable is a string that denotes a path for +the schema file of Common Workflow Language." + :type '(choice (const :tag "None" nil) + (file :tag "Schema file")) + :safe #'flycheck-string-or-nil-p) + +(flycheck-define-checker cwl + "A CWL syntax checker using Schema Salad validator. + +Requires Schema Salad 2.6.20171101113912 or newer. +See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'." + :command ("schema-salad-tool" + "--quiet" + "--print-oneline" + (eval flycheck-cwl-schema-path) + source-inplace) + :error-patterns + ((error line-start + (file-name) ":" line ":" column ":" (zero-or-more blank) + (message (one-or-more not-newline)) + line-end)) + :modes cwl-mode) + +(defconst flycheck-d-module-re + (rx "module" (one-or-more (syntax whitespace)) + (group (one-or-more (not (syntax whitespace)))) + (zero-or-more (syntax whitespace)) + ";") + "Regular expression to match a D module declaration.") + +(defun flycheck-d-base-directory () + "Get the relative base directory path for this module." + (let* ((file-name (buffer-file-name)) + (module-file (if (and file-name + (string= (file-name-nondirectory file-name) + "package.d")) + (directory-file-name (file-name-directory file-name)) + file-name))) + (flycheck-module-root-directory + (flycheck-find-in-buffer flycheck-d-module-re) + module-file))) + +(flycheck-def-option-var flycheck-dmd-include-path nil d-dmd + "A list of include directories for dmd. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of dmd. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.18")) + +(flycheck-def-args-var flycheck-dmd-args d-dmd + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker d-dmd + "A D syntax checker using the DMD compiler. + +Requires DMD 2.066 or newer. See URL `https://dlang.org/'." + :command ("dmd" + "-debug" ; Compile in debug mode + "-o-" ; Don't generate an object file + "-vcolumns" ; Add columns in output + "-wi" ; Compilation will continue even if there are warnings + (eval (concat "-I" (flycheck-d-base-directory))) + (option-list "-I" flycheck-dmd-include-path concat) + (eval flycheck-dmd-args) + (source ".d")) + :error-patterns + ((error line-start + (file-name) "(" line "," column "): Error: " (message) + line-end) + (warning line-start (file-name) "(" line "," column "): " + (or "Warning" "Deprecation") ": " (message) line-end) + (info line-start (file-name) "(" line "," column "): " + (one-or-more " ") (message) line-end)) + :modes d-mode) + +(flycheck-define-checker dockerfile-hadolint + "A Dockerfile syntax checker using the hadolint. + +See URL `http://github.com/hadolint/hadolint/'." + :command ("hadolint" "-") + :standard-input t + :error-patterns + ((error line-start + (file-name) ":" line ":" column " " (message) + line-end) + (warning line-start + (file-name) ":" line " " (id (one-or-more alnum)) " " (message) + line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "/dev/stdin" errors))) + :modes dockerfile-mode) + +(defun flycheck-credo--working-directory (&rest _ignored) + "Check if `credo' is installed as dependency in the application." + (and buffer-file-name + (locate-dominating-file buffer-file-name "deps/credo"))) + +(flycheck-def-option-var flycheck-elixir-credo-strict nil elixir-credo + "Enable strict mode in `credo'. + +When non-nil, pass the `--strict' flag to credo." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "32")) + +(flycheck-define-checker elixir-credo + "An Elixir checker for static code analysis using Credo. + +See `http://credo-ci.org/'." + :command ("mix" "credo" + (option-flag "--strict" flycheck-elixir-credo-strict) + "--format" "flycheck" + "--read-from-stdin" source-original) + :standard-input t + :working-directory flycheck-credo--working-directory + :enabled flycheck-credo--working-directory + :error-patterns + ((info line-start + (file-name) ":" line (optional ":" column) ": " + (or "F" "R" "C") ": " (message) line-end) + (warning line-start + (file-name) ":" line (optional ":" column) ": " + (or "D" "W") ": " (message) line-end)) + :modes elixir-mode) + +(defconst flycheck-this-emacs-executable + (concat invocation-directory invocation-name) + "The path to the currently running Emacs executable.") + +(defconst flycheck-emacs-args '("-Q" "--batch") + "Common arguments to Emacs invocations.") + +(defmacro flycheck-prepare-emacs-lisp-form (&rest body) + "Prepare BODY for use as check form in a subprocess." + (declare (indent 0)) + `(flycheck-sexp-to-string + '(progn + (defvar jka-compr-inhibit) + (unwind-protect + ;; Flycheck inhibits compression of temporary files, thus we + ;; must not attempt to decompress. + (let ((jka-compr-inhibit t)) + ;; Strip option-argument separator from arguments, if present + (when (equal (car command-line-args-left) "--") + (setq command-line-args-left (cdr command-line-args-left))) + ,@body) + ;; Prevent Emacs from processing the arguments on its own, see + ;; https://github.com/flycheck/flycheck/issues/319 + (setq command-line-args-left nil))))) + +(defun flycheck-emacs-lisp-bytecomp-config-form () + "Prepare an Emacs Lisp form to set byte-compiler variables." + (flycheck-sexp-to-string + `(progn + (require 'bytecomp) + (setq byte-compile-root-dir + ,(if buffer-file-name + (file-name-directory buffer-file-name) + default-directory))))) + +(defconst flycheck-emacs-lisp-check-form + (flycheck-prepare-emacs-lisp-form + ;; Keep track of the generated bytecode files, to delete them after byte + ;; compilation. + (require 'bytecomp) + (defvar flycheck-byte-compiled-files nil) + (let ((byte-compile-dest-file-function + (lambda (source) + (let ((temp-file (make-temp-file (file-name-nondirectory source)))) + (push temp-file flycheck-byte-compiled-files) + temp-file)))) + (unwind-protect + (byte-compile-file (car command-line-args-left)) + (mapc (lambda (f) (ignore-errors (delete-file f))) + flycheck-byte-compiled-files)) + (when (bound-and-true-p flycheck-emacs-lisp-check-declare) + (check-declare-file (car command-line-args-left)))))) + +(flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp + "Load path to use in the Emacs Lisp syntax checker. + +When set to `inherit', use the `load-path' of the current Emacs +session during syntax checking. + +When set to a list of strings, add each directory in this list to +the `load-path' before invoking the byte compiler. Relative +paths in this list are expanded against the `default-directory' +of the buffer to check. + +When nil, do not explicitly set the `load-path' during syntax +checking. The syntax check only uses the built-in `load-path' of +Emacs in this case. + +Note that changing this variable can lead to wrong results of the +syntax check, e.g. if an unexpected version of a required library +is used." + :type '(choice (const :tag "Inherit current `load-path'" inherit) + (repeat :tag "Load path" directory)) + :risky t + :package-version '(flycheck . "0.14")) + +(flycheck-def-option-var flycheck-emacs-lisp-initialize-packages + 'auto emacs-lisp + "Whether to initialize packages in the Emacs Lisp syntax checker. + +When nil, never initialize packages. When `auto', initialize +packages only when checking `user-init-file' or files from +`user-emacs-directory'. For any other non-nil value, always +initialize packages. + +When initializing packages is enabled the `emacs-lisp' syntax +checker calls `package-initialize' before byte-compiling the file +to be checked. It also sets `package-user-dir' according to +`flycheck-emacs-lisp-package-user-dir'." + :type '(choice (const :tag "Do not initialize packages" nil) + (const :tag "Initialize packages for configuration only" auto) + (const :tag "Always initialize packages" t)) + :risky t + :package-version '(flycheck . "0.14")) + +(defconst flycheck-emacs-lisp-package-initialize-form + (flycheck-sexp-to-string + '(with-demoted-errors "Error during package initialization: %S" + (package-initialize))) + "Form used to initialize packages.") + +(defun flycheck-option-emacs-lisp-package-initialize (value) + "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'." + (let ((shall-initialize + (if (eq value 'auto) + (or (flycheck-in-user-emacs-directory-p + (or buffer-file-name default-directory)) + ;; `user-init-file' is nil in non-interactive sessions. Now, + ;; no user would possibly use Flycheck in a non-interactive + ;; session, but our unit tests run non-interactively, so we + ;; have to handle this case anyway + (and user-init-file buffer-file-name + (flycheck-same-files-p buffer-file-name user-init-file))) + value))) + (when shall-initialize + ;; If packages shall be initialized, return the corresponding form, + ;; otherwise make Flycheck ignore the option by returning nil. + flycheck-emacs-lisp-package-initialize-form))) + +(flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp + "Package directory for the Emacs Lisp syntax checker. + +If set to a string set `package-user-dir' to the value of this +variable before initializing packages. If set to nil just inherit +the value of `package-user-dir' from the running Emacs session. + +This variable has no effect, if +`flycheck-emacs-lisp-initialize-packages' is nil." + :type '(choice (const :tag "Default package directory" nil) + (directory :tag "Custom package directory")) + :risky t + :package-version '(flycheck . "0.14")) + +(defun flycheck-option-emacs-lisp-package-user-dir (value) + "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'." + ;; Inherit the package directory from our Emacs session + (let ((value (or value (bound-and-true-p package-user-dir)))) + (when value + (flycheck-sexp-to-string `(setq package-user-dir ,value))))) + +(flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp + "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’." + :type '(choice (const :tag "Do not check declare forms" nil) + (const :tag "Check declare forms" t)) + :risky t + :package-version '(flycheck . "31")) + +(defun flycheck-option-emacs-lisp-check-declare (value) + "Option VALUE filter for `flycheck-emacs-lisp-check-declare'." + (when value + (flycheck-sexp-to-string + `(progn + (defvar flycheck-emacs-lisp-check-declare) + (setq flycheck-emacs-lisp-check-declare ,value))))) + +(defun flycheck--emacs-lisp-enabled-p () + "Check whether to enable Emacs Lisp checkers in the current buffer." + (not + (or + ;; Do not check buffers used for autoloads generation during package + ;; installation. These buffers are too short-lived for being checked, and + ;; doing so causes spurious errors. See + ;; https://github.com/flycheck/flycheck/issues/45 and + ;; https://github.com/bbatsov/prelude/issues/248. We must also not check + ;; compilation buffers, but as these are ephemeral, Flycheck won't check + ;; them anyway. + (flycheck-autoloads-file-p) + ;; Cask/Carton and dir-locals files contain data, not code, and don't need + ;; to follow Checkdoc conventions either. + (and (buffer-file-name) + (member (file-name-nondirectory (buffer-file-name)) + '("Cask" "Carton" ".dir-locals.el" ".dir-locals-2.el")))))) + +(flycheck-define-checker emacs-lisp + "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler. + +See Info Node `(elisp)Byte Compilation'." + :command ("emacs" (eval flycheck-emacs-args) + (eval + (let ((path (pcase flycheck-emacs-lisp-load-path + (`inherit load-path) + (p (seq-map #'expand-file-name p))))) + (flycheck-prepend-with-option "--directory" path))) + (option "--eval" flycheck-emacs-lisp-package-user-dir nil + flycheck-option-emacs-lisp-package-user-dir) + (option "--eval" flycheck-emacs-lisp-initialize-packages nil + flycheck-option-emacs-lisp-package-initialize) + (option "--eval" flycheck-emacs-lisp-check-declare nil + flycheck-option-emacs-lisp-check-declare) + "--eval" (eval (flycheck-emacs-lisp-bytecomp-config-form)) + "--eval" (eval flycheck-emacs-lisp-check-form) + "--" + source-inplace) + :error-patterns + ((error line-start (file-name) ":" line ":" column ":" + (zero-or-more whitespace) "Error:" (zero-or-more whitespace) + (message (zero-or-more not-newline) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + (warning line-start (file-name) ":" line ":" column ":" + (zero-or-more whitespace) "Warning:" (zero-or-more whitespace) + (message (zero-or-more not-newline) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + (warning line-start (file-name) ":" line (optional ":" column) ":" + (zero-or-more whitespace) "Warning (check-declare): said\n" + (message (zero-or-more " " (zero-or-more not-newline)) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + ;; The following is for Emacs 24 ‘check-declare-file’, which uses a + ;; less informative format. + (warning line-start "Warning (check-declare): " (file-name) " said " + (message (zero-or-more not-newline)) + line-end)) + :error-filter + (lambda (errors) + (flycheck-fill-empty-line-numbers + (flycheck-collapse-error-message-whitespace + (flycheck-sanitize-errors errors)))) + :modes (emacs-lisp-mode lisp-interaction-mode) + :enabled flycheck--emacs-lisp-enabled-p + :predicate + (lambda () + ;; Do not check buffers that should not be byte-compiled. The checker + ;; process will refuse to compile these, which would confuse Flycheck + (not (bound-and-true-p no-byte-compile))) + :next-checkers (emacs-lisp-checkdoc)) + +(defconst flycheck-emacs-lisp-checkdoc-form + (flycheck-prepare-emacs-lisp-form + (unless (require 'elisp-mode nil 'no-error) + ;; TODO: Fallback for Emacs 24, remove when dropping support for 24 + (require 'lisp-mode)) + (require 'checkdoc) + + (let ((source (car command-line-args-left)) + ;; Remember the default directory of the process + (process-default-directory default-directory)) + ;; Note that we deliberately use our custom approach even despite of + ;; `checkdoc-file' which was added to Emacs 25.1. While it's conceptually + ;; the better thing, its implementation has too many flaws to be of use + ;; for us. + (with-temp-buffer + (insert-file-contents source 'visit) + (setq buffer-file-name source) + ;; And change back to the process default directory to make file-name + ;; back-substutition work + (setq default-directory process-default-directory) + (with-demoted-errors "Error in checkdoc: %S" + ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to + ;; parse sexps and identify docstrings correctly; see + ;; https://github.com/flycheck/flycheck/issues/833 + (delay-mode-hooks (emacs-lisp-mode)) + (setq delayed-mode-hooks nil) + (checkdoc-current-buffer t) + (with-current-buffer checkdoc-diagnostic-buffer + (princ (buffer-substring-no-properties (point-min) (point-max))) + (kill-buffer))))))) + +(defconst flycheck-emacs-lisp-checkdoc-variables + '(checkdoc-symbol-words + checkdoc-arguments-in-order-flag + checkdoc-force-history-flag + checkdoc-permit-comma-termination-flag + checkdoc-force-docstrings-flag + checkdoc-package-keywords-flag + checkdoc-spellcheck-documentation-flag + checkdoc-verb-check-experimental-flag + checkdoc-max-keyref-before-warn + sentence-end-double-space) + "Variables inherited by the checkdoc subprocess.") + +(defun flycheck-emacs-lisp-checkdoc-variables-form () + "Make a sexp to pass relevant variables to a checkdoc subprocess. + +Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'." + `(progn + ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt))) + (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables)))) + +(flycheck-define-checker emacs-lisp-checkdoc + "An Emacs Lisp style checker using CheckDoc. + +The checker runs `checkdoc-current-buffer'." + :command ("emacs" (eval flycheck-emacs-args) + "--eval" (eval (flycheck-sexp-to-string + (flycheck-emacs-lisp-checkdoc-variables-form))) + "--eval" (eval flycheck-emacs-lisp-checkdoc-form) + "--" source) + :error-patterns + ((info line-start (file-name) ":" line ": " (message) line-end)) + :modes (emacs-lisp-mode) + :enabled flycheck--emacs-lisp-enabled-p) + +(dolist (checker '(emacs-lisp emacs-lisp-checkdoc)) + (setf (car (flycheck-checker-get checker 'command)) + flycheck-this-emacs-executable)) + +(defun flycheck-ember-template--check-for-config (&rest _ignored) + "Check the required config file is available up the file system." + (and buffer-file-name + (locate-dominating-file buffer-file-name ".template-lintrc.js"))) + +(defun flycheck-ember-template--parse-error (output checker buffer) + "Parse Ember-template-lint errors/warnings from JSON OUTPUT. +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at + .line + .column + (pcase .severity + (2 'error) + (1 'warning) + (_ 'warning)) + .message + :id .rule + :checker checker + :buffer buffer + :filename (buffer-file-name buffer)))) + (cdr (car (car (flycheck-parse-json output)))))) + +(flycheck-def-config-file-var flycheck-ember-template-lintrc + ember-template + ".template-lintrc.js") + +(flycheck-define-checker ember-template + "An Ember template checker using ember-template-lint." + :command ("ember-template-lint" + (config-file "--config-path" flycheck-ember-template-lintrc) + "--filename" source-original + "--json") + :standard-input t + :error-parser flycheck-ember-template--parse-error + :modes web-mode + :enabled flycheck-ember-template--check-for-config + :working-directory flycheck-ember-template--check-for-config) + +(flycheck-def-option-var flycheck-erlang-include-path nil erlang + "A list of include directories for Erlang. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of erlc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-erlang-library-path nil erlang + "A list of library directories for Erlang. + +The value of this variable is a list of strings, where each +string is a directory to add to the library path of erlc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Library directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker erlang + "An Erlang syntax checker using the Erlang interpreter. + +See URL `http://www.erlang.org/'." + :command ("erlc" + "-o" temporary-directory + (option-list "-I" flycheck-erlang-include-path) + (option-list "-pa" flycheck-erlang-library-path) + "-Wall" + source) + :error-patterns + ((warning line-start (file-name) ":" line ": Warning:" (message) line-end) + (error line-start (file-name) ":" line ": " (message) line-end)) + :modes erlang-mode + :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name)))) + +(defun flycheck--contains-rebar-config (dir-name) + "Return DIR-NAME if rebar config file exists in DIR-NAME, nil otherwise." + (when (or (file-exists-p (expand-file-name "rebar.config" dir-name)) + (file-exists-p (expand-file-name "rebar.config.script" dir-name))) + dir-name)) + +(defun flycheck--locate-rebar3-project-root + (file-name &optional prev-file-name acc) + "Find the top-most rebar project root for source FILE-NAME. + +A project root directory is any directory containing a +rebar.config file. Find the top-most directory to move out of any +nested dependencies. + +FILE-NAME is a source file for which to find the project. + +PREV-FILE-NAME helps us prevent infinite looping + +ACC is an accumulator that keeps the list of results, the first +non-nil of which will be our project root. + +Return the absolute path to the directory" + (if (string= file-name prev-file-name) + (car (remove nil acc)) + (let ((current-dir (file-name-directory file-name))) + (flycheck--locate-rebar3-project-root + (directory-file-name current-dir) + file-name + (cons (flycheck--contains-rebar-config current-dir) acc))))) + +(defun flycheck-rebar3-project-root (&optional _checker) + "Return directory where rebar.config is located." + (flycheck--locate-rebar3-project-root buffer-file-name)) + +(flycheck-def-option-var flycheck-erlang-rebar3-profile nil erlang-rebar3 + "The rebar3 profile to use. + +The profile used when compiling, if VALUE is nil \"test\" will be used +when the file is located in test directory, otherwise \"default\" will be +used as profile." + :type '(choice (const :tag "Automatic" nil) + (string :tag "Profile")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) + +(defun flycheck-erlang-rebar3-get-profile () + "Return rebar3 profile. + +Use flycheck-erlang-rebar3-profile if set, otherwise use test or eqc profile if +directory name is \"test\" or \"eqc\", or else \"default\"." + (or + flycheck-erlang-rebar3-profile + (with-no-warnings + ;; `seq-contains-p' is only in seq >= 2.21 + (seq-contains '("test" "eqc") + (and buffer-file-name + (file-name-base + (directory-file-name + (file-name-directory buffer-file-name)))))) + "default")) + +(flycheck-define-checker erlang-rebar3 + "An Erlang syntax checker using the rebar3 build tool." + :command ("rebar3" "as" (eval (flycheck-erlang-rebar3-get-profile)) "compile") + :error-parser flycheck-parse-with-patterns-without-color + :error-patterns + ((warning line-start + (file-name) ":" line ": Warning:" (message) line-end) + (error line-start + (file-name) ":" line ": " (message) line-end)) + :modes erlang-mode + :enabled flycheck-rebar3-project-root + :predicate flycheck-buffer-saved-p + :working-directory flycheck-rebar3-project-root) + +(flycheck-define-checker eruby-erubis + "An eRuby syntax checker using the `erubis' command. + +See URL `http://www.kuwata-lab.com/erubis/'." + :command ("erubis" "-z" source) + :error-patterns + ((error line-start (file-name) ":" line ": " (message) line-end)) + :modes (html-erb-mode rhtml-mode) + :next-checkers ((warning . eruby-ruumba))) + +(flycheck-def-config-file-var flycheck-ruumbarc eruby-ruumba ".ruumba.yml") + +(flycheck-def-option-var flycheck-ruumba-lint-only nil eruby-ruumba + "Whether to only report code issues in Ruumba. + +When non-nil, only report code issues in Ruumba, via `--lint'. +Otherwise report style issues as well." + :safe #'booleanp + :type 'boolean + :package-version '(flycheck . "32")) + +(flycheck-define-checker eruby-ruumba + "An eRuby syntax and style checker using the Ruumba tool. + +You need at least Ruumba 0.1.7 for this syntax checker. + +See URL `https://github.com/ericqweinstein/ruumba'." + :command ("ruumba" + "--display-cop-names" + "--force-exclusion" + "--format" "emacs" + "--cache" "false" + (config-file "--config" flycheck-ruumbarc) + (option-flag "--lint" flycheck-ruumba-lint-only) + ;; Ruumba takes the original file name as argument when reading + ;; from standard input + "--stdin" source-original) + :standard-input t + :working-directory flycheck-ruby--find-project-root + :error-patterns + ((info line-start (file-name) ":" line ":" column ": C: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end) + (warning line-start (file-name) ":" line ":" column ": W: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end) + (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end)) + :modes (html-erb-mode rhtml-mode)) + +(flycheck-def-args-var flycheck-gfortran-args fortran-gfortran + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran + "A list of include directories for GCC Fortran. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of gcc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gfortran-language-standard "f95" + fortran-gfortran + "The language standard to use in GFortran. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran + "The source code layout to use in GFortran. + +The value of this variable is one of the following symbols: + +nil + Let gfortran determine the layout from the extension + +`free' + Use free form layout + + +`fixed' + Use fixed form layout + +In any other case, an error is signaled." + :type '(choice (const :tag "Guess layout from extension" nil) + (const :tag "Free form layout" free) + (const :tag "Fixed form layout" fixed)) + :safe (lambda (value) (or (not value) (memq value '(free fixed)))) + :package-version '(flycheck . "0.20")) + +(defun flycheck-option-gfortran-layout (value) + "Option VALUE filter for `flycheck-gfortran-layout'." + (pcase value + (`nil nil) + (`free "free-form") + (`fixed "fixed-form") + (_ (error "Invalid value for flycheck-gfortran-layout: %S" value)))) + +(flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra") + fortran-gfortran + "A list of warnings for GCC Fortran. + +The value of this variable is a list of strings, where each string +is the name of a warning category to enable. By default, all +recommended warnings and some extra warnings are enabled (as by +`-Wall' and `-Wextra' respectively). + +Refer to the gfortran manual at URL +`https://gcc.gnu.org/onlinedocs/gfortran/' for more information +about warnings" + :type '(choice (const :tag "No additional warnings" nil) + (repeat :tag "Additional warnings" + (string :tag "Warning name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker fortran-gfortran + "An Fortran syntax checker using GCC. + +Uses GCC's Fortran compiler gfortran. See URL +`https://gcc.gnu.org/onlinedocs/gfortran/'." + :command ("gfortran" + "-fsyntax-only" + "-fshow-column" + ;; Do not visually indicate the source location + "-fno-diagnostics-show-caret" + ;; Do not show the corresponding warning group + "-fno-diagnostics-show-option" + ;; Fortran has similar include processing as C/C++ + "-iquote" (eval (flycheck-c/c++-quoted-include-directory)) + (option "-std=" flycheck-gfortran-language-standard concat) + (option "-f" flycheck-gfortran-layout concat + flycheck-option-gfortran-layout) + (option-list "-W" flycheck-gfortran-warnings concat) + (option-list "-I" flycheck-gfortran-include-path concat) + (eval flycheck-gfortran-args) + source) + :error-patterns + ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n") + (or (= 3 (zero-or-more not-newline) "\n") "") + (or "Error" "Fatal Error") ": " + (message) line-end) + (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n") + (or (= 3 (zero-or-more not-newline) "\n") "") + "Warning: " (message) line-end)) + :modes (fortran-mode f90-mode)) + +(flycheck-define-checker go-gofmt + "A Go syntax and style checker using the gofmt utility. + +See URL `https://golang.org/cmd/gofmt/'." + :command ("gofmt") + :standard-input t + :error-patterns + ((error line-start ":" line ":" column ": " + (message) line-end)) + :modes go-mode + :next-checkers ((warning . go-golint) + ;; Fall back, if go-golint doesn't exist + (warning . go-vet) + ;; Fall back, if go-vet doesn't exist + (warning . go-build) (warning . go-test) + (warning . go-errcheck) + (warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-golint + "A Go style checker using Golint. + +See URL `https://github.com/golang/lint'." + :command ("golint" source) + :error-patterns + ((warning line-start (file-name) ":" line ":" column ": " (message) line-end)) + :modes go-mode + :next-checkers (go-vet + ;; Fall back, if go-vet doesn't exist + go-build go-test go-errcheck go-unconvert)) + +(flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet + "A list of print-like functions for `go vet'. + +Go vet will check these functions for format string problems and +issues, such as a mismatch between the number of formats used, +and the number of arguments given. + +Each entry is in the form Name:N where N is the zero-based +argument position of the first argument involved in the print: +either the format or the first print argument for non-formatted +prints. For example, if you have Warn and Warnf functions that +take an io.Writer as their first argument, like Fprintf, +-printfuncs=Warn:1,Warnf:1 " + :type '(repeat :tag "print-like functions" + (string :tag "function")) + :safe #'flycheck-string-list-p) + +(flycheck-define-checker go-vet + "A Go syntax checker using the `go vet' command. + +See URL `https://golang.org/cmd/go/' and URL +`https://golang.org/cmd/vet/'." + :command ("go" "vet" + (option "-printf.funcs=" flycheck-go-vet-print-functions concat + flycheck-option-comma-separated-list) + (source ".go")) + :error-patterns + ((warning line-start (file-name) ":" line ": " (message) line-end)) + :modes go-mode + :next-checkers (go-build + go-test + ;; Fall back if `go build' or `go test' can be used + go-errcheck + go-unconvert + go-staticcheck) + :verify (lambda (_) + (let* ((go (flycheck-checker-executable 'go-vet)) + (have-vet (member "vet" (ignore-errors + (process-lines go "tool"))))) + (list + (flycheck-verification-result-new + :label "go tool vet" + :message (if have-vet "present" "missing") + :face (if have-vet 'success '(bold error))))))) + +(flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test) + "Whether to install dependencies in `go build' and `go test'. + +If non-nil automatically install dependencies with `go build' +while syntax checking." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.25")) + +(flycheck-def-option-var flycheck-go-build-tags nil + (go-build go-test go-errcheck go-staticcheck) + "A list of tags for `go build'. + +Each item is a string with a tag to be given to `go build'." + :type '(repeat (string :tag "Tag")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.25")) + + +(flycheck-def-option-var flycheck-go-version nil go-staticcheck + "The version of go that should be targeted by `staticcheck'. + +Should be a string representing a version, like 1.6 or 1.11.4. +See `https://staticcheck.io/docs/#targeting-go-versions' for +details." + :type '(choice (const :tag "Unspecified" nil) + (string :tag "Version")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.32")) + +(flycheck-define-checker go-build + "A Go syntax and type checker using the `go build' command. + +Requires Go 1.6 or newer. See URL `https://golang.org/cmd/go'." + :command ("go" "build" + (option-flag "-i" flycheck-go-build-install-deps) + ;; multiple tags are listed as "dev debug ..." + (option-list "-tags=" flycheck-go-build-tags concat) + "-o" null-device) + :error-patterns + ((error line-start (file-name) ":" line ":" + (optional column ":") " " + (message (one-or-more not-newline) + (zero-or-more "\n\t" (one-or-more not-newline))) + line-end) + ;; Catch error message about multiple packages in a directory, which doesn't + ;; follow the standard error message format. + (info line-start + (message "can't load package: package " + (one-or-more (not (any ?: ?\n))) + ": found packages " + (one-or-more not-newline)) + line-end)) + :error-filter + (lambda (errors) + (dolist (error errors) + (unless (flycheck-error-line error) + ;; Flycheck ignores errors without line numbers, but the error + ;; message about multiple packages in a directory doesn't come with a + ;; line number, so inject a fake one. + (setf (flycheck-error-line error) 1))) + errors) + :modes go-mode + :predicate (lambda () + (and (flycheck-buffer-saved-p) + (not (string-suffix-p "_test.go" (buffer-file-name))))) + :next-checkers ((warning . go-errcheck) + (warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-test + "A Go syntax and type checker using the `go test' command. + +Requires Go 1.6 or newer. See URL `https://golang.org/cmd/go'." + :command ("go" "test" + (option-flag "-i" flycheck-go-build-install-deps) + (option-list "-tags=" flycheck-go-build-tags concat) + "-c" "-o" null-device) + :error-patterns + ((error line-start (file-name) ":" line ":" + (optional column ":") " " + (message (one-or-more not-newline) + (zero-or-more "\n\t" (one-or-more not-newline))) + line-end)) + :modes go-mode + :predicate + (lambda () (and (flycheck-buffer-saved-p) + (string-suffix-p "_test.go" (buffer-file-name)))) + :next-checkers ((warning . go-errcheck) + (warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-errcheck + "A Go checker for unchecked errors. + +Requires errcheck newer than commit 8515d34 (Aug 28th, 2015). + +See URL `https://github.com/kisielk/errcheck'." + :command ("errcheck" + "-abspath" + (option-list "-tags=" flycheck-go-build-tags concat) + ".") + :error-patterns + ((warning line-start + (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t") + (message) + line-end)) + :error-filter + (lambda (errors) + (let ((errors (flycheck-sanitize-errors errors))) + (dolist (err errors) + (-when-let (message (flycheck-error-message err)) + ;; Improve the messages reported by errcheck to make them more clear. + (setf (flycheck-error-message err) + (format "Ignored `error` returned from `%s`" message))))) + errors) + :modes go-mode + :predicate (lambda () (flycheck-buffer-saved-p)) + :next-checkers ((warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-unconvert + "A Go checker looking for unnecessary type conversions. + +See URL `https://github.com/mdempsky/unconvert'." + :command ("unconvert" ".") + :error-patterns + ((warning line-start (file-name) ":" line ":" column ": " (message) line-end)) + :modes go-mode + :predicate (lambda () (flycheck-buffer-saved-p))) + +(flycheck-define-checker go-staticcheck + "A Go checker that performs static analysis and linting using +the `staticcheck' command. + +`staticcheck' is explicitly fully compatible with \"the last two +versions of go\". `staticheck' can target earlier versions (with +limited features) if `flycheck-go-version' is set. See URL +`https://staticcheck.io/'." + :command ("staticcheck" "-f" "json" + (option-list "-tags" flycheck-go-build-tags concat) + (option "-go" flycheck-go-version)) + + :error-parser flycheck-parse-go-staticcheck + :modes go-mode) + +(flycheck-define-checker groovy + "A groovy syntax checker using groovy compiler API. + +See URL `http://www.groovy-lang.org'." + :command ("groovy" "-e" + "import org.codehaus.groovy.control.* + +unit = new CompilationUnit() +unit.addSource(\"input\", System.in) + +try { + unit.compile(Phases.CONVERSION) +} catch (MultipleCompilationErrorsException e) { + e.errorCollector.write(new PrintWriter(System.out, true), null) +}") + :standard-input t + :error-patterns + ((error line-start "input: " line ":" (message) + " @ line " line ", column " column "." line-end)) + :modes groovy-mode) + +(flycheck-define-checker haml + "A Haml syntax checker using the Haml compiler. + +See URL `http://haml.info'." + :command ("haml" "-c" "--stdin") + :standard-input t + :error-patterns + ((error line-start "Syntax error on line " line ": " (message) line-end) + (error line-start ":" line ": syntax error, " (message) line-end)) + :modes haml-mode) + +(flycheck-define-checker handlebars + "A Handlebars syntax checker using the Handlebars compiler. + +See URL `http://handlebarsjs.com/'." + :command ("handlebars" "-i-") + :standard-input t + :error-patterns + ((error line-start + "Error: Parse error on line " line ":" (optional "\r") "\n" + (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n" + (message) line-end)) + :modes (handlebars-mode handlebars-sgml-mode web-mode) + :predicate + (lambda () + (if (eq major-mode 'web-mode) + ;; Check if this is a handlebars file since web-mode does not store the + ;; non-canonical engine name + (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps)) + (pattern (cdr (assoc "handlebars" regexp-alist)))) + (and pattern (buffer-file-name) + (string-match-p pattern (buffer-file-name)))) + t))) + +(defconst flycheck-haskell-module-re + (rx line-start (zero-or-more (or "\n" (any space))) + "module" (one-or-more (or "\n" (any space))) + (group (one-or-more (not (any space "(" "\n"))))) + "Regular expression for a Haskell module name.") + +(flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc) + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc + "Whether to enable nix support in stack. + +When non-nil, stack will append '--nix' flag to any call." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "26")) + +(flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc + "Override project stack.yaml file. + +The value of this variable is a file path that refers to a yaml +file for the current stack project. Relative file paths are +resolved against the checker's working directory. When non-nil, +stack will get overridden value via `--stack-yaml'." + :type '(choice (const :tag "Unspecified" nil) + (file :tag "Project file")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc + "Whether to disable the user package database in GHC. + +When non-nil, disable the user package database in GHC, via +`-no-user-package-db'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc + "Additional module databases for GHC. + +The value of this variable is a list of strings, where each +string is a directory of a package database. Each package +database is given to GHC via `-package-db'." + :type '(repeat (directory :tag "Package database")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-ghc-search-path nil + (haskell-stack-ghc haskell-ghc) + "Module search path for (Stack) GHC. + +The value of this variable is a list of strings, where each +string is a directory containing Haskell modules. Each directory +is added to the GHC search path via `-i'." + :type '(repeat (directory :tag "Module directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-ghc-language-extensions nil + (haskell-stack-ghc haskell-ghc) + "Language extensions for (Stack) GHC. + +The value of this variable is a list of strings, where each +string is a Haskell language extension, as in the LANGUAGE +pragma. Each extension is enabled via `-X'." + :type '(repeat (string :tag "Language extension")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.19")) + +(defvar flycheck-haskell-ghc-cache-directory nil + "The cache directory for `ghc' output.") + +(defun flycheck-haskell-ghc-cache-directory () + "Get the cache location for `ghc' output. + +If no cache directory exists yet, create one and return it. +Otherwise return the previously used cache directory." + (setq flycheck-haskell-ghc-cache-directory + (or flycheck-haskell-ghc-cache-directory + (make-temp-file "flycheck-haskell-ghc-cache" 'directory)))) + +(defun flycheck--locate-dominating-file-matching (directory regexp) + "Search for a file in directory hierarchy starting at DIRECTORY. + +Look up the directory hierarchy from DIRECTORY for a directory +containing a file that matches REGEXP." + (locate-dominating-file + directory + (lambda (dir) + (directory-files dir nil regexp t)))) + +(defun flycheck-haskell--find-stack-default-directory () + "Find a directory to run haskell-stack-ghc. + +Return a parent directory with a stack*.y[a]ml file, or the +directory returned by \"stack path --project-root\"." + (or + (when (buffer-file-name) + (flycheck--locate-dominating-file-matching + (file-name-directory (buffer-file-name)) + (rx "stack" (* any) "." (or "yml" "yaml") eos))) + (-when-let* ((stack (funcall flycheck-executable-find "stack")) + (output (ignore-errors + (process-lines stack + "--no-install-ghc" + "path" "--project-root"))) + (stack-dir (car output))) + (and (file-directory-p stack-dir) stack-dir)))) + +(defun flycheck-haskell--ghc-find-default-directory (_checker) + "Find a parent directory containing a cabal or package.yaml file." + (when (buffer-file-name) + (flycheck--locate-dominating-file-matching + (file-name-directory (buffer-file-name)) + "\\.cabal\\'\\|\\`package\\.yaml\\'"))) + +(flycheck-define-checker haskell-stack-ghc + "A Haskell syntax and type checker using `stack ghc'. + +See URL `https://github.com/commercialhaskell/stack'." + :command ("stack" + "--no-install-ghc" + (option "--stack-yaml" flycheck-ghc-stack-project-file) + (option-flag "--nix" flycheck-ghc-stack-use-nix) + "ghc" "--" "-Wall" "-no-link" + "-outputdir" (eval (flycheck-haskell-ghc-cache-directory)) + (option-list "-X" flycheck-ghc-language-extensions concat) + (option-list "-i" flycheck-ghc-search-path concat) + (eval (concat + "-i" + (flycheck-module-root-directory + (flycheck-find-in-buffer flycheck-haskell-module-re)))) + (eval flycheck-ghc-args) + "-x" (eval + (pcase major-mode + (`haskell-mode "hs") + (`haskell-literate-mode "lhs"))) + source) + :error-patterns + ((warning line-start (file-name) ":" line ":" column ":" + (or " " "\n ") (in "Ww") "arning:" + (optional " " "[" (id (one-or-more not-newline)) "]") + (optional "\n") + (message + (one-or-more " ") (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more (not (any ?\n ?|))))) + line-end) + (error line-start (file-name) ":" line ":" column ":" (optional " error:") + (or (message (one-or-more not-newline)) + (and "\n" + (message + (one-or-more " ") (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more (not (any ?\n ?|))))))) + line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors (flycheck-dedent-error-messages errors))) + :modes (haskell-mode haskell-literate-mode) + :next-checkers ((warning . haskell-hlint)) + :working-directory (lambda (_) + (flycheck-haskell--find-stack-default-directory)) + :enabled flycheck-haskell--find-stack-default-directory + :verify (lambda (_) + (let* ((stack (flycheck-haskell--find-stack-default-directory))) + (list + (flycheck-verification-result-new + :label "stack config" + :message (or stack "Not found") + :face (if stack 'success '(bold error))))))) + +(flycheck-define-checker haskell-ghc + "A Haskell syntax and type checker using ghc. + +See URL `https://www.haskell.org/ghc/'." + :command ("ghc" "-Wall" "-no-link" + "-outputdir" (eval (flycheck-haskell-ghc-cache-directory)) + (option-flag "-no-user-package-db" + flycheck-ghc-no-user-package-database) + (option-list "-package-db" flycheck-ghc-package-databases) + (option-list "-i" flycheck-ghc-search-path concat) + ;; Include the parent directory of the current module tree, to + ;; properly resolve local imports + (eval (concat + "-i" + (flycheck-module-root-directory + (flycheck-find-in-buffer flycheck-haskell-module-re)))) + (option-list "-X" flycheck-ghc-language-extensions concat) + (eval flycheck-ghc-args) + "-x" (eval + (pcase major-mode + (`haskell-mode "hs") + (`haskell-literate-mode "lhs"))) + source) + :error-patterns + ((warning line-start (file-name) ":" line ":" column ":" + (or " " "\n ") (in "Ww") "arning:" + (optional " " "[" (id (one-or-more not-newline)) "]") + (optional "\n") + (message + (one-or-more " ") (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more (not (any ?\n ?|))))) + line-end) + (error line-start (file-name) ":" line ":" column ":" (optional " error:") + (or (message (one-or-more not-newline)) + (and "\n" + (message + (one-or-more " ") (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more (not (any ?\n ?|))))))) + line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors (flycheck-dedent-error-messages errors))) + :modes (haskell-mode haskell-literate-mode) + :next-checkers ((warning . haskell-hlint)) + :working-directory flycheck-haskell--ghc-find-default-directory) + +(flycheck-def-config-file-var flycheck-hlintrc haskell-hlint "HLint.hs") + +(flycheck-def-args-var flycheck-hlint-args haskell-hlint + :package-version '(flycheck . "0.25")) + +(flycheck-def-option-var flycheck-hlint-language-extensions + nil haskell-hlint + "Extensions list to enable for hlint. + +The value of this variable is a list of strings, where each +string is a name of extension to enable in +hlint (e.g. \"QuasiQuotes\")." + :type '(repeat :tag "Extensions" (string :tag "Extension")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-hlint-ignore-rules + nil haskell-hlint + "Ignore rules list for hlint checks. + +The value of this variable is a list of strings, where each +string is an ignore rule (e.g. \"Use fmap\")." + :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-hlint-hint-packages + nil haskell-hlint + "Hint packages to include for hlint checks. + +The value of this variable is a list of strings, where each +string is a default hint package (e.g. (\"Generalise\" +\"Default\" \"Dollar\"))." + :type '(repeat :tag "Hint packages" (string :tag "Hint package")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker haskell-hlint + "A Haskell style checker using hlint. + +See URL `https://github.com/ndmitchell/hlint'." + :command ("hlint" + (option-list "-X" flycheck-hlint-language-extensions concat) + (option-list "-i=" flycheck-hlint-ignore-rules concat) + (option-list "-h" flycheck-hlint-hint-packages concat) + (config-file "-h" flycheck-hlintrc) + (eval flycheck-hlint-args) + source-inplace) + :error-patterns + ((info line-start + (file-name) ":" line ":" column (optional "-" end-column) + ": Suggestion: " + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end) + (warning line-start + (file-name) ":" line ":" column (optional "-" end-column) + ": Warning: " + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end) + (error line-start + (file-name) ":" line ":" column (optional "-" end-column) + ": Error: " + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end)) + :modes (haskell-mode haskell-literate-mode)) + +(flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc") + +(flycheck-define-checker html-tidy + "A HTML syntax and style checker using Tidy. + +See URL `https://github.com/htacg/tidy-html5'." + :command ("tidy" (config-file "-config" flycheck-tidyrc) + "-lang" "en" + "-e" "-q") + :standard-input t + :error-patterns + ((error line-start + "line " line + " column " column + " - Error: " (message) line-end) + (warning line-start + "line " line + " column " column + " - Warning: " (message) line-end)) + :modes (html-mode mhtml-mode nxhtml-mode)) + +(flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc") + +(flycheck-def-option-var flycheck-jshint-extract-javascript nil + javascript-jshint + "Whether jshint should extract Javascript from HTML. + +If nil no extract rule is given to jshint. If `auto' only +extract Javascript if a HTML file is detected. If `always' or +`never' extract Javascript always or never respectively. + +Refer to the jshint manual at the URL +`http://jshint.com/docs/cli/#flags' for more information." + :type + '(choice (const :tag "No extraction rule" nil) + (const :tag "Try to extract Javascript when detecting HTML files" + auto) + (const :tag "Always try to extract Javascript" always) + (const :tag "Never try to extract Javascript" never)) + :safe #'symbolp + :package-version '(flycheck . "26")) + +(flycheck-define-checker javascript-jshint + "A Javascript syntax and style checker using jshint. + +See URL `http://www.jshint.com'." + :command ("jshint" "--reporter=checkstyle" + "--filename" source-original + (config-file "--config" flycheck-jshintrc) + (option "--extract=" flycheck-jshint-extract-javascript + concat flycheck-option-symbol) + "-") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter + (lambda (errors) + (flycheck-remove-error-file-names + "stdin" (flycheck-dequalify-error-ids errors))) + :modes (js-mode js2-mode js3-mode rjsx-mode)) + +(flycheck-def-args-var flycheck-eslint-args javascript-eslint + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint + "A list of directories with custom rules for ESLint. + +The value of this variable is a list of strings, where each +string is a directory with custom rules for ESLint. + +Refer to the ESLint manual at URL +`http://eslint.org/docs/user-guide/command-line-interface#--rulesdir' +for more information about the custom directories." + :type '(repeat (directory :tag "Custom rules directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "29")) + +(defun flycheck-eslint-config-exists-p () + "Whether there is a valid eslint config for the current buffer." + (eql 0 (flycheck-call-checker-process + 'javascript-eslint nil nil nil + "--print-config" (or buffer-file-name "index.js")))) + +(defun flycheck-parse-eslint (output checker buffer) + "Parse ESLint errors/warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://eslint.org' for more information about ESLint." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at + .line + .column + (pcase .severity + (2 'error) + (1 'warning) + (_ 'warning)) + .message + :id .ruleId + :checker checker + :buffer buffer + :filename (buffer-file-name buffer) + :end-line .endLine + :end-column .endColumn))) + (let-alist (caar (flycheck-parse-json output)) + .messages))) + +(defun flycheck-eslint--find-working-directory (_checker) + "Look for a working directory to run ESLint CHECKER in. + +This will be the directory that contains the `node_modules' +directory. If no such directory is found in the directory +hierarchy, it looks first for `.eslintignore' and then for +`.eslintrc' files to detect the project root." + (let* ((regex-config (concat "\\`\\.eslintrc" + "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'"))) + (when buffer-file-name + (or (locate-dominating-file buffer-file-name "node_modules") + (locate-dominating-file buffer-file-name ".eslintignore") + (locate-dominating-file + (file-name-directory buffer-file-name) + (lambda (directory) + (> (length (directory-files directory nil regex-config t)) 0))))))) + +(flycheck-define-checker javascript-eslint + "A Javascript syntax and style checker using eslint. + +See URL `https://eslint.org/'." + :command ("eslint" "--format=json" + (option-list "--rulesdir" flycheck-eslint-rules-directories) + (eval flycheck-eslint-args) + "--stdin" "--stdin-filename" source-original) + :standard-input t + :error-parser flycheck-parse-eslint + :enabled (lambda () (flycheck-eslint-config-exists-p)) + :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode + typescript-mode) + :working-directory flycheck-eslint--find-working-directory + :verify + (lambda (_) + (let* ((default-directory + (flycheck-compute-working-directory 'javascript-eslint)) + (have-config (flycheck-eslint-config-exists-p))) + (list + (flycheck-verification-result-new + :label "config file" + :message (if have-config "found" "missing or incorrect") + :face (if have-config 'success '(bold error)))))) + :error-explainer + (lambda (err) + (let ((error-code (flycheck-error-id err)) + (url "https://eslint.org/docs/rules/%s")) + (and error-code + ;; skip non-builtin rules + (not ;; `seq-contains-p' is only in seq >= 2.21 + (with-no-warnings (seq-contains error-code ?/))) + `(url . ,(format url error-code)))))) + +(flycheck-define-checker javascript-standard + "A Javascript code and style checker for the (Semi-)Standard Style. + +This checker works with `standard' and `semistandard', defaulting +to the former. To use it with the latter, set +`flycheck-javascript-standard-executable' to `semistandard'. + +See URL `https://github.com/standard/standard' and URL +`https://github.com/Flet/semistandard'." + :command ("standard" "--stdin") + :standard-input t + :error-patterns + ((error line-start " :" line ":" column ":" (message) line-end)) + :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode)) + +(flycheck-define-checker json-jsonlint + "A JSON syntax and style checker using jsonlint. + +See URL `https://github.com/zaach/jsonlint'." + ;; We can't use standard input for jsonlint, because it doesn't output errors + ;; anymore when using -c -q with standard input :/ + :command ("jsonlint" "-c" "-q" source) + :error-patterns + ((error line-start + (file-name) + ": line " line + ", col " column ", " + (message) line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors (flycheck-increment-error-columns errors))) + :modes json-mode) + +(flycheck-define-checker json-python-json + "A JSON syntax checker using Python json.tool module. + +See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'." + :command ("python3" "-m" "json.tool" source + ;; Send the pretty-printed output to the null device + null-device) + :error-patterns + ((error line-start + (message) ": line " line " column " column + ;; Ignore the rest of the line which shows the char position. + (one-or-more not-newline) + line-end)) + :modes json-mode + ;; The JSON parser chokes if the buffer is empty and has no JSON inside + :predicate flycheck-buffer-nonempty-p) + +(flycheck-define-checker json-jq + "JSON checker using the jq tool. + +This checker accepts multiple consecutive JSON values in a +single input, which is useful for jsonlines data. + +See URL `https://stedolan.github.io/jq/'." + :command ("jq" "." source null-device) + ;; Example error message: + ;; parse error: Expected another key-value pair at line 3, column 1 + :error-patterns + ((error line-start + (optional "parse error: ") + (message) "at line " line ", column " column + (zero-or-more not-newline) line-end)) + :modes json-mode) + +(flycheck-define-checker jsonnet + "A Jsonnet syntax checker using the jsonnet binary. + +See URL `https://jsonnet.org'." + :command ("jsonnet" source-inplace) + :error-patterns + ((error line-start "STATIC ERROR: " (file-name) ":" + (or (seq line ":" column (zero-or-one (seq "-" end-column))) + (seq "(" line ":" column ")" "-" + "(" end-line ":" end-column ")")) + ": " (message) line-end) + (error line-start "RUNTIME ERROR: " (message) "\n" + (? "\t" (file-name) ":" ;; first line of the backtrace + (or (seq line ":" column (zero-or-one (seq "-" end-column))) + (seq "(" line ":" column ")" "-" + "(" end-line ":" end-column ")"))))) + :error-filter + (lambda (errs) + ;; Some errors are missing line numbers. See URL + ;; `https://github.com/google/jsonnet/issues/786'. + (dolist (err errs) + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 1))) + (flycheck-sanitize-errors errs)) + :modes jsonnet-mode) + +(flycheck-define-checker less + "A LESS syntax checker using lessc. + +Requires lessc 1.4 or newer. + +See URL `http://lesscss.org'." + :command ("lessc" "--lint" "--no-color" + "-") + :standard-input t + :error-patterns + ((error line-start (one-or-more word) ":" + (message) + " in - on line " line + ", column " column ":" + line-end)) + :modes less-css-mode) + +(flycheck-define-checker less-stylelint + "A LESS syntax and style checker using stylelint. + +See URL `http://stylelint.io/'." + :command ("stylelint" + (eval flycheck-stylelint-args) + "--syntax" "less" + (option-flag "--quiet" flycheck-stylelint-quiet) + (config-file "--config" flycheck-stylelintrc)) + :standard-input t + :error-parser flycheck-parse-stylelint + :predicate flycheck-buffer-nonempty-p + :modes (less-css-mode)) + +(flycheck-define-checker llvm-llc + "Flycheck LLVM IR checker using llc. + +See URL `http://llvm.org/docs/CommandGuide/llc.html'." + :command ("llc" "-o" null-device source) + :error-patterns + ((error line-start + ;; llc prints the executable path + (zero-or-one (minimal-match (one-or-more not-newline)) ": ") + (file-name) ":" line ":" column ": error: " (message) + line-end)) + :error-filter + (lambda (errors) + ;; sanitize errors occurring in inline assembly + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "" errors))) + :modes llvm-mode) + +(flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc") + +(flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck + "The standards to use in luacheck. + +The value of this variable is either a list of strings denoting +the standards to use, or nil to pass nothing to luacheck. When +non-nil, pass the standards via one or more `--std' options." + :type '(choice (const :tag "Default" nil) + (repeat :tag "Custom standards" + (string :tag "Standard name"))) + :safe #'flycheck-string-list-p) +(make-variable-buffer-local 'flycheck-luacheck-standards) + +(flycheck-define-checker lua-luacheck + "A Lua syntax checker using luacheck. + +See URL `https://github.com/mpeterv/luacheck'." + :command ("luacheck" + "--formatter" "plain" + "--codes" ; Show warning codes + "--no-color" + (option-list "--std" flycheck-luacheck-standards) + (config-file "--config" flycheck-luacheckrc) + "--filename" source-original + ;; Read from standard input + "-") + :standard-input t + :error-patterns + ((warning line-start + (optional (file-name)) + ":" line ":" column + ": (" (id "W" (one-or-more digit)) ") " + (message) line-end) + (error line-start + (optional (file-name)) + ":" line ":" column ":" + ;; `luacheck' before 0.11.0 did not output codes for errors, hence + ;; the ID is optional here + (optional " (" (id "E" (one-or-more digit)) ") ") + (message) line-end)) + :modes lua-mode) + +(flycheck-define-checker lua + "A Lua syntax checker using the Lua compiler. + +See URL `http://www.lua.org/'." + :command ("luac" "-p" "-") + :standard-input t + :error-patterns + ((error line-start + ;; Skip the name of the luac executable. + (minimal-match (zero-or-more not-newline)) + ": stdin:" line ": " (message) line-end)) + :modes lua-mode) + +(flycheck-define-checker opam + "A Opam syntax and style checker using opam lint. + +See URL `https://opam.ocaml.org/doc/man/opam-lint.html'." + :command ("opam" "lint" "-") + :standard-input t + :error-patterns + ((error line-start ; syntax error + (one-or-more space) "error " (id ?2) + ": File format error" + (or (and " at line " line ", column " column ": " (message)) + (and ": " (message))) + line-end) + (error line-start + (one-or-more space) "error " (id ?3) + (minimal-match (zero-or-more not-newline)) + "at line " line ", column " column ": " (message) + line-end) + (error line-start + (one-or-more space) "error " (id (one-or-more num)) + ": " (message (one-or-more not-newline)) + line-end) + (warning line-start + (one-or-more space) "warning " (id (one-or-more num)) + ": " (message) + line-end)) + :error-filter + (lambda (errors) + (flycheck-increment-error-columns + (flycheck-fill-empty-line-numbers errors))) + :modes tuareg-opam-mode) + +(flycheck-def-option-var flycheck-perl-include-path nil perl + "A list of include directories for Perl. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of Perl. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-perl-module-list nil perl + "A list of modules to use for Perl. + +The value of this variable is a list of strings, where each +string is a module to 'use' in Perl." + :type '(repeat :tag "Module") + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker perl + "A Perl syntax checker using the Perl interpreter. + +See URL `https://www.perl.org'." + :command ("perl" "-w" "-c" + (option-list "-I" flycheck-perl-include-path) + (option-list "-M" flycheck-perl-module-list concat)) + :standard-input t + :error-patterns + ((error line-start (minimal-match (message)) + " at - line " line + (or "." (and ", " (zero-or-more not-newline))) line-end)) + :modes (perl-mode cperl-mode) + :next-checkers (perl-perlcritic)) + +(flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic + "The message severity for Perl Critic. + +The value of this variable is a severity level as integer, for +the `--severity' option to Perl Critic." + :type '(integer :tag "Severity level") + :safe #'integerp + :package-version '(flycheck . "0.18")) + +(flycheck-def-option-var flycheck-perlcritic-theme nil perl-perlcritic + "The theme expression for Perl Critic. + +The value of this variable is passed as the `--theme' option to +`Perl::Critic'. See the documentation of `Perl::Critic' for +details." + :type '(choice (const :tag "None" nil) + (string :tag "Theme expression")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32-csv")) + +(flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic + ".perlcriticrc" + :package-version '(flycheck . "26")) + +(flycheck-define-checker perl-perlcritic + "A Perl syntax checker using Perl::Critic. + +See URL `https://metacpan.org/pod/Perl::Critic'." + :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n" + (config-file "--profile" flycheck-perlcriticrc) + (option "--severity" flycheck-perlcritic-severity nil + flycheck-option-int) + (option "--theme" flycheck-perlcritic-theme)) + :standard-input t + :error-patterns + ((info line-start + "STDIN/" line "/" column "/" (any "1") "/" + (id (one-or-more (not (any "/")))) "/" (message) + line-end) + (warning line-start + "STDIN/" line "/" column "/" (any "234") "/" + (id (one-or-more (not (any "/")))) "/" (message) + line-end) + (error line-start + "STDIN/" line "/" column "/" (any "5") "/" + (id (one-or-more (not (any "/")))) "/" (message) + line-end)) + :modes (cperl-mode perl-mode)) + +(flycheck-define-checker php + "A PHP syntax checker using the PHP command line interpreter. + +See URL `http://php.net/manual/en/features.commandline.php'." + :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1" + "-d" "log_errors=0" source) + :error-patterns + ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " " + (message) " in " (file-name) " on line " line line-end)) + :modes (php-mode php+-mode) + :next-checkers ((warning . php-phpmd) + (warning . php-phpcs))) + +(flycheck-def-option-var flycheck-phpmd-rulesets + '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode") + php-phpmd + "The rule sets for PHP Mess Detector. + +Set default rule sets and custom rule set files. + +See section \"Using multiple rule sets\" in the PHP Mess Detector +manual at URL `https://phpmd.org/documentation/index.html'." + :type '(repeat :tag "rule sets" + (string :tag "A filename or rule set")) + :safe #'flycheck-string-list-p) + +(flycheck-define-checker php-phpmd + "A PHP style checker using PHP Mess Detector. + +See URL `https://phpmd.org/'." + :command ("phpmd" source "xml" + (eval (flycheck-option-comma-separated-list + flycheck-phpmd-rulesets))) + :error-parser flycheck-parse-phpmd + :modes (php-mode php+-mode) + :next-checkers (php-phpcs)) + +(flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs + "The coding standard for PHP CodeSniffer. + +When nil, use the default standard from the global PHP +CodeSniffer configuration. When set to a string, pass the string +to PHP CodeSniffer which will interpret it as name as a standard, +or as path to a standard specification." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Standard name or file")) + :safe #'flycheck-string-or-nil-p) + +(flycheck-define-checker php-phpcs + "A PHP style checker using PHP Code Sniffer. + +Needs PHP Code Sniffer 2.6 or newer. + +See URL `http://pear.php.net/package/PHP_CodeSniffer/'." + :command ("phpcs" "--report=checkstyle" + ;; Use -q flag to force quiet mode + ;; Quiet mode prevents errors from extra output when phpcs has + ;; been configured with show_progress enabled + "-q" + (option "--standard=" flycheck-phpcs-standard concat) + ;; Some files are not detected correctly + ;; so it is necessary to pass the extension. + (eval + (-when-let* ((fname buffer-file-name) + (ext (file-name-extension fname))) + (concat "--extensions=" ext))) + + ;; Pass original file name to phpcs. We need to concat explicitly + ;; here, because phpcs really insists to get option and argument as + ;; a single command line argument :| + (eval (when (buffer-file-name) + (concat "--stdin-path=" (buffer-file-name)))) + ;; Read from standard input + "-") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "STDIN" errors))) + :modes (php-mode php+-mode) + ;; phpcs seems to choke on empty standard input, hence skip phpcs if the + ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907 + :predicate flycheck-buffer-nonempty-p) + +(flycheck-define-checker processing + "Processing command line tool. + +See https://github.com/processing/processing/wiki/Command-Line" + :command ("processing-java" "--force" + ;; Don't change the order of these arguments, processing is pretty + ;; picky + (eval (concat "--sketch=" (file-name-directory (buffer-file-name)))) + (eval (concat "--output=" (flycheck-temp-dir-system))) + "--build") + :error-patterns + ((error line-start (file-name) ":" line ":" column + (zero-or-more (or digit ":")) (message) line-end)) + :modes processing-mode + ;; This syntax checker needs a file name + :predicate (lambda () (buffer-file-name))) + +(defun flycheck-proselint-parse-errors (output checker buffer) + "Parse proselint json output errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://proselint.com/' for more information about proselint." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at-pos + .start + (pcase .severity + (`"suggestion" 'info) + (`"warning" 'warning) + (`"error" 'error) + ;; Default to error + (_ 'error)) + .message + :id .check + :buffer buffer + :checker checker + ;; See https://github.com/amperser/proselint/issues/1048 + :end-pos .end))) + (let-alist (car (flycheck-parse-json output)) + .data.errors))) + +(flycheck-define-checker proselint + "Flycheck checker using Proselint. + +See URL `http://proselint.com/'." + :command ("proselint" "--json" "-") + :standard-input t + :error-parser flycheck-proselint-parse-errors + :modes (text-mode markdown-mode gfm-mode message-mode org-mode)) + +(flycheck-def-option-var flycheck-protoc-import-path nil protobuf-protoc + "A list of directories to resolve import directives. + +The value of this variable is a list of strings, where each +string is a directory to add to the import path. Relative paths +are relative to the file being checked." + :type '(repeat (directory :tag "Import directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker protobuf-protoc + "A protobuf syntax checker using the protoc compiler. + +See URL `https://developers.google.com/protocol-buffers/'." + :command ("protoc" "--error_format" "gcc" + (eval (concat "--java_out=" (flycheck-temp-dir-system))) + ;; Add the current directory to resolve imports + (eval (concat "--proto_path=" + (file-name-directory (buffer-file-name)))) + ;; Add other import paths; this needs to be after the current + ;; directory to produce the right output. See URL + ;; `https://github.com/flycheck/flycheck/pull/1655' + (option-list "--proto_path=" flycheck-protoc-import-path concat) + source-inplace) + :error-patterns + ((info line-start (file-name) ":" line ":" column + ": note: " (message) line-end) + (error line-start (file-name) ":" line ":" column + ": " (message) line-end) + (error line-start + (message "In file included from") " " (file-name) ":" line ":" + column ":" line-end)) + :modes protobuf-mode + :predicate (lambda () (buffer-file-name))) + +(defun flycheck-prototool-project-root (&optional _checker) + "Return the nearest directory holding the prototool.yaml configuration." + (and buffer-file-name + (locate-dominating-file buffer-file-name "prototool.yaml"))) + +(flycheck-define-checker protobuf-prototool + "A protobuf syntax checker using prototool. + +See URL `https://github.com/uber/prototool'." + :command ("prototool" "lint" source-original) + :error-patterns + ((warning line-start (file-name) ":" line ":" column ":" (message) line-end)) + :modes protobuf-mode + :enabled flycheck-prototool-project-root + :predicate flycheck-buffer-saved-p) + +(flycheck-define-checker pug + "A Pug syntax checker using the pug compiler. + +See URL `https://pugjs.org/'." + :command ("pug" "-p" (eval (expand-file-name (buffer-file-name)))) + :standard-input t + :error-patterns + ;; errors with includes/extends (e.g. missing files) + ((error "Error: " (message) (zero-or-more not-newline) "\n" + (zero-or-more not-newline) "at " + (zero-or-more not-newline) " line " line) + ;; error when placing anything other than a mixin or + ;; block at the top-level of an extended template + ;; also unknown filters + (error line-start "Error: " (file-name) ":" + line ":" column "\n\n" (message) line-end) + ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.) + (error line-start + (optional "Type") "Error: " (file-name) ":" + line (optional ":" column) + (zero-or-more not-newline) "\n" + (one-or-more (or (zero-or-more not-newline) "|" + (zero-or-more not-newline) "\n") + (zero-or-more "-") (zero-or-more not-newline) "|" + (zero-or-more not-newline) "\n") + (zero-or-more not-newline) "\n" + (one-or-more + (zero-or-more not-newline) "|" + (zero-or-more not-newline) "\n") + (zero-or-more not-newline) "\n" + (message) + line-end)) + :modes pug-mode) + +(flycheck-define-checker puppet-parser + "A Puppet DSL syntax checker using puppet's own parser. + +See URL `https://puppet.com/'." + :command ("puppet" "parser" "validate" "--color=false") + :standard-input t + :error-patterns + ( + ;; Patterns for Puppet 4 + (error line-start "Error: Could not parse for environment " + (one-or-more (in "a-z" "0-9" "_")) ":" + (message) "(line: " line ", column: " column ")" line-end) + ;; Errors from Puppet < 4 + (error line-start "Error: Could not parse for environment " + (one-or-more (in "a-z" "0-9" "_")) ":" + (message (minimal-match (one-or-more anything))) + " at line " line line-end) + (error line-start + ;; Skip over the path of the Puppet executable + (minimal-match (zero-or-more not-newline)) + ": Could not parse for environment " (one-or-more word) + ": " (message (minimal-match (zero-or-more anything))) + " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end)) + :modes puppet-mode + :next-checkers ((warning . puppet-lint))) + +(flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint + ".puppet-lint.rc" + :package-version '(flycheck . "26")) + +(flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint + "Disabled checkers for `puppet-lint'. + +The value of this variable is a list of strings, where each +string is the name of a check to disable (e.g. \"80chars\" or +\"double_quoted_strings\"). + +See URL `http://puppet-lint.com/checks/' for a list of all checks +and their names." + :type '(repeat (string :tag "Check Name")) + :package-version '(flycheck . "26")) + +(defun flycheck-puppet-lint-disabled-arg-name (check) + "Create an argument to disable a puppetlint CHECK." + (concat "--no-" check "-check")) + +(flycheck-define-checker puppet-lint + "A Puppet DSL style checker using puppet-lint. + +See URL `http://puppet-lint.com/'." + ;; We must check the original file, because Puppetlint is quite picky on the + ;; names of files and there place in the directory structure, to comply with + ;; Puppet's autoload directory layout. For instance, a class foo::bar is + ;; required to be in a file foo/bar.pp. Any other place, such as a Flycheck + ;; temporary file will cause an error. + :command ("puppet-lint" + (config-file "--config" flycheck-puppet-lint-rc) + "--log-format" + "%{path}:%{line}:%{kind}: %{message} (%{check})" + (option-list "" flycheck-puppet-lint-disabled-checks concat + flycheck-puppet-lint-disabled-arg-name) + source-original) + :error-patterns + ((warning line-start (file-name) ":" line ":warning: " (message) line-end) + (error line-start (file-name) ":" line ":error: " (message) line-end)) + :modes puppet-mode + ;; Since we check the original file, we can only use this syntax checker if + ;; the buffer is actually linked to a file, and if it is not modified. + :predicate flycheck-buffer-saved-p) + +(defun flycheck-python-run-snippet (checker snippet) + "Run a python SNIPPET and return the output. + +CHECKER's executable is assumed to be a Python REPL." + (-when-let (output (flycheck-call-checker-process-for-output + checker nil nil "-c" snippet)) + (string-trim output))) + +(defun flycheck-python-get-path (checker) + "Compute the current Python path (CHECKER is a Python REPL) ." + (flycheck-python-run-snippet checker "import sys; print(sys.path[1:])")) + +(defun flycheck-python-find-module (checker module) + "Check if a Python MODULE is available (CHECKER is a Python REPL)." + (flycheck-python-run-snippet + checker (concat "import sys; sys.path.pop(0);" + (format "import %s; print(%s.__file__)" module module)))) + +(defun flycheck-python-needs-module-p (checker) + "Determines whether CHECKER needs to be invoked through Python. + +Previous versions of Flycheck called pylint and flake8 directly, +while new version call them through `python -c'. This check +ensures that we don't break existing code; it also allows people +who use virtualenvs to run globally-installed checkers." + (not (string-match-p (rx (or "pylint" "pylint3" "flake8") + (or "-script.pyw" ".exe" ".bat" "") + eos) + (flycheck-checker-executable checker)))) + +(defun flycheck-python-verify-module (checker module) + "Verify that a Python MODULE is available. + +Return nil if CHECKER's executable is not a Python REPL. This +function's is suitable for a checker's :verify." + (when (flycheck-python-needs-module-p checker) + (let ((mod-path (flycheck-python-find-module checker module))) + (list (flycheck-verification-result-new + :label (format "`%s' module" module) + :message (if mod-path (format "Found at %S" mod-path) + (format "Missing; sys.path is %s" + (flycheck-python-get-path checker))) + :face (if mod-path 'success '(bold error))))))) + +(defun flycheck-python-module-args (checker module-name) + "Compute arguments to pass to CHECKER's executable to run MODULE-NAME. + +Return nil if CHECKER's executable is not a Python REPL. +Otherwise, return a list starting with -c (-m is not enough +because it adds the current directory to Python's path)." + (when (flycheck-python-needs-module-p checker) + `("-c" ,(concat "import sys;sys.path.pop(0);import runpy;" + (format "runpy.run_module(%S)" module-name))))) + +(flycheck-def-config-file-var flycheck-flake8rc python-flake8 ".flake8rc") + +(flycheck-def-option-var flycheck-flake8-error-level-alist + '(("^E9.*$" . error) ; Syntax errors from pep8 + ("^F82.*$" . error) ; undefined variables from pyflakes + ("^F83.*$" . error) ; Duplicate arguments from flake8 + ("^D.*$" . info) ; Docstring issues from flake8-pep257 + ("^N.*$" . info) ; Naming issues from pep8-naming + ) + python-flake8 + "An alist mapping flake8 error IDs to Flycheck error levels. + +Each item in this list is a cons cell `(PATTERN . LEVEL)' where +PATTERN is a regular expression matched against the error ID, and +LEVEL is a Flycheck error level symbol. + +Each PATTERN is matched in the order of appearance in this list +against the error ID. If it matches the ID, the level of the +corresponding error is set to LEVEL. An error that is not +matched by any PATTERN defaults to warning level. + +The default value of this option matches errors from flake8 +itself and from the following flake8 plugins: + +- pep8-naming +- flake8-pep257 + +You may add your own mappings to this option in order to support +further flake8 plugins." + :type '(repeat (cons (regexp :tag "Error ID pattern") + (symbol :tag "Error level"))) + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8 + "The maximum McCabe complexity of methods. + +If nil, do not check the complexity of methods. If set to an +integer, report any complexity greater than the value of this +variable as warning. + +If set to an integer, this variable overrules any similar setting +in the configuration file denoted by `flycheck-flake8rc'." + :type '(choice (const :tag "Do not check McCabe complexity" nil) + (integer :tag "Maximum complexity")) + :safe #'integerp) + +(flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8 + "The maximum length of lines. + +If set to an integer, the value of this variable denotes the +maximum length of lines, overruling any similar setting in the +configuration file denoted by `flycheck-flake8rc'. An error will +be reported for any line longer than the value of this variable. + +If set to nil, use the maximum line length from the configuration +file denoted by `flycheck-flake8rc', or the PEP 8 recommendation +of 79 characters if there is no configuration with this setting." + :type '(choice (const :tag "Default value") + (integer :tag "Maximum line length in characters")) + :safe #'integerp) + +(defun flycheck-flake8-fix-error-level (err) + "Fix the error level of ERR. + +Update the error level of ERR according to +`flycheck-flake8-error-level-alist'." + (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist) + (when (string-match-p pattern (flycheck-error-id err)) + (setf (flycheck-error-level err) level))) + err) + +(defun flycheck-flake8--find-project-root (_checker) + "Find setup.cfg in a parent directory of the current buffer." + ;; This is a workaround for `https://gitlab.com/pycqa/flake8/issues/517'; see + ;; also `https://github.com/flycheck/flycheck/issues/1722' + (locate-dominating-file (or buffer-file-name default-directory) "setup.cfg")) + +(flycheck-define-checker python-flake8 + "A Python syntax and style checker using Flake8. + +Requires Flake8 3.0 or newer. See URL +`https://flake8.readthedocs.io/'." + ;; Not calling flake8 directly makes it easier to switch between different + ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055. + :command ("python3" + (eval (flycheck-python-module-args 'python-flake8 "flake8")) + "--format=default" + (config-file "--append-config" flycheck-flake8rc) + (option "--max-complexity" flycheck-flake8-maximum-complexity nil + flycheck-option-int) + (option "--max-line-length" flycheck-flake8-maximum-line-length nil + flycheck-option-int) + (eval (when buffer-file-name + (concat "--stdin-display-name=" buffer-file-name))) + "-") + :standard-input t + :working-directory flycheck-flake8--find-project-root + :error-filter (lambda (errors) + (let ((errors (flycheck-sanitize-errors errors))) + (seq-map #'flycheck-flake8-fix-error-level errors))) + :error-patterns + ((warning line-start + (file-name) ":" line ":" (optional column ":") " " + (id (one-or-more (any alpha)) (one-or-more digit)) " " + (message (one-or-more not-newline)) + line-end)) + :enabled (lambda () + (or (not (flycheck-python-needs-module-p 'python-flake8)) + (flycheck-python-find-module 'python-flake8 "flake8"))) + :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8")) + :modes python-mode + :next-checkers ((warning . python-pylint) + (warning . python-mypy))) + +(flycheck-def-config-file-var flycheck-pylintrc python-pylint ".pylintrc") + +(flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint + "Whether to use pylint message symbols or message codes. + +A pylint message has both an opaque identifying code (such as `F0401') and a +more meaningful symbolic code (such as `import-error'). This option governs +which should be used and reported to the user." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.25")) + +(defun flycheck-parse-pylint (output checker buffer) + "Parse JSON OUTPUT of CHECKER on BUFFER as Pylint errors." + (mapcar (lambda (err) + (let-alist err + ;; Pylint can return -1 as a line or a column, hence the call to + ;; `max'. See `https://github.com/flycheck/flycheck/issues/1383'. + (flycheck-error-new-at + (and .line (max .line 1)) + (and .column (max (1+ .column) 1)) + (pcase .type + ;; See "pylint/utils.py" + ((or "fatal" "error") 'error) + ((or "info" "convention") 'info) + ((or "warning" "refactor" _) 'warning)) + ;; Drop lines showing the error in context + (and (string-match (rx (*? nonl) eol) .message) + (match-string 0 .message)) + :id (if flycheck-pylint-use-symbolic-id .symbol .message-id) + :checker checker + :buffer buffer + :filename .path))) + (car (flycheck-parse-json output)))) + +(flycheck-define-checker python-pylint + "A Python syntax and style checker using Pylint. + +This syntax checker requires Pylint 1.0 or newer. + +See URL `https://www.pylint.org/'." + ;; --reports=n disables the scoring report. + ;; Not calling pylint directly makes it easier to switch between different + ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055. + :command ("python3" + (eval (flycheck-python-module-args 'python-pylint "pylint")) + "--reports=n" + "--output-format=json" + (config-file "--rcfile=" flycheck-pylintrc concat) + ;; Need `source-inplace' for relative imports (e.g. `from .foo + ;; import bar'), see https://github.com/flycheck/flycheck/issues/280 + source-inplace) + :error-parser flycheck-parse-pylint + :enabled (lambda () + (or (not (flycheck-python-needs-module-p 'python-pylint)) + (flycheck-python-find-module 'python-pylint "pylint"))) + :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint")) + :error-explainer (lambda (err) + (-when-let (id (flycheck-error-id err)) + (apply + #'flycheck-call-checker-process-for-output + 'python-pylint nil t + (append + (flycheck-python-module-args 'python-pylint "pylint") + (list (format "--help-msg=%s" id)))))) + :modes python-mode + :next-checkers ((warning . python-mypy))) + +(flycheck-define-checker python-pycompile + "A Python syntax checker using Python's builtin compiler. + +See URL `https://docs.python.org/3.4/library/py_compile.html'." + :command ("python3" "-m" "py_compile" source) + :error-patterns + ;; Python 2.7 + ((error line-start " File \"" (file-name) "\", line " line "\n" + (>= 2 (zero-or-more not-newline) "\n") + "SyntaxError: " (message) line-end) + (error line-start "Sorry: IndentationError: " + (message) "(" (file-name) ", line " line ")" + line-end) + ;; 2.6 + (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'")))) + "', ('" (file-name (one-or-more (not (any "'")))) "', " + line ", " column ", " (one-or-more not-newline) line-end)) + :modes python-mode + :next-checkers ((warning . python-mypy))) + +(defun flycheck-pyright--parse-error (output checker buffer) + "Parse pyright errors/warnings from JSON OUTPUT. +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively." + (seq-map + (lambda (err) + (let-alist err + (flycheck-error-new-at + (+ 1 .range.start.line) + (+ 1 .range.start.character) + (pcase .severity + ("error" 'error) + ("warning" 'warning) + (_ 'warning)) + .message + :end-line (+ 1 .range.end.line) + :end-column (+ 1 .range.end.character) + :checker checker + :buffer buffer + :filename (buffer-file-name buffer)))) + (cdr (nth 2 (car (flycheck-parse-json output)))))) + +(defun flycheck-pyright--find-project-root (_checker) + "Find project root by searching for pyright config file." + (locate-dominating-file + (or buffer-file-name default-directory) "pyrightconfig.json")) + +(flycheck-define-checker python-pyright + "Static type checker for Python + +See URL https://github.com/microsoft/pyright." + :command ("pyright" + "--outputjson" + source-inplace) + :working-directory flycheck-pyright--find-project-root + :error-parser flycheck-pyright--parse-error + :modes python-mode) + +(define-obsolete-variable-alias 'flycheck-python-mypy-ini + 'flycheck-python-mypy-config "32") + +(flycheck-def-config-file-var flycheck-python-mypy-config python-mypy + '("mypy.ini" "setup.cfg")) + +(flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy + "Directory used to write .mypy_cache directories." + :type '(choice + (const :tag "Write to the working directory" nil) + (const :tag "Never write .mypy_cache directories" null-device) + (string :tag "Path")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker python-mypy + "Mypy syntax and type checker. Requires mypy>=0.580. + +See URL `http://mypy-lang.org/'." + :command ("mypy" + "--show-column-numbers" + (config-file "--config-file" flycheck-python-mypy-config) + (option "--cache-dir" flycheck-python-mypy-cache-dir) + source-original) + :error-patterns + ((error line-start (file-name) ":" line (optional ":" column) + ": error:" (message) line-end) + (warning line-start (file-name) ":" line (optional ":" column) + ": warning:" (message) line-end) + (info line-start (file-name) ":" line (optional ":" column) + ": note:" (message) line-end)) + :modes python-mode + ;; Ensure the file is saved, to work around + ;; https://github.com/python/mypy/issues/4746. + :predicate flycheck-buffer-saved-p) + +(flycheck-def-option-var flycheck-lintr-caching t r-lintr + "Whether to enable caching in lintr. + +By default, lintr caches all expressions in a file and re-checks +only those that have changed. Setting this option to nil +disables caching in case there are problems." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr + "Linters to use with lintr. + +The value of this variable is a string containing an R +expression, which selects linters for lintr." + :type 'string + :risky t + :package-version '(flycheck . "0.23")) + +(defun flycheck-r-has-lintr (checker) + "Whether CHECKER (R) has installed the `lintr' library." + (eql 0 (flycheck-call-checker-process + checker nil nil nil + "--slave" "--restore" "--no-save" "-e" + "library('lintr')"))) + +(flycheck-define-checker r-lintr + "An R style and syntax checker using the lintr package. + +See URL `https://github.com/jimhester/lintr'." + :command ("R" "--slave" "--restore" "--no-save" "-e" + (eval (concat + "library(lintr);" + "try(lint(commandArgs(TRUE)" + ", cache=" (if flycheck-lintr-caching "TRUE" "FALSE") + ", " flycheck-lintr-linters + "))")) + "--args" source) + :error-patterns + ((info line-start (file-name) ":" line ":" column ": style: " (message) + line-end) + (warning line-start (file-name) ":" line ":" column ": warning: " (message) + line-end) + (error line-start (file-name) ":" line ":" column ": error: " (message) + line-end)) + :modes (ess-mode ess-r-mode) + :predicate + ;; Don't check ESS files which do not contain R, and make sure that lintr is + ;; actually available + (lambda () + (and (equal ess-language "S") + (flycheck-r-has-lintr 'r-lintr))) + :verify (lambda (checker) + (let ((has-lintr (flycheck-r-has-lintr checker))) + (list + (flycheck-verification-result-new + :label "lintr library" + :message (if has-lintr "present" "missing") + :face (if has-lintr 'success '(bold error))))))) + +(defun flycheck-racket-has-expand-p (checker) + "Whether the executable of CHECKER provides the `expand' command." + (eql 0 (flycheck-call-checker-process checker nil nil nil "expand"))) + +(flycheck-define-checker racket + "A Racket syntax checker with `raco expand'. + +The `compiler-lib' racket package is required for this syntax +checker. + +See URL `https://racket-lang.org/'." + :command ("raco" "expand" source-inplace) + :predicate + (lambda () + (and (or (not (eq major-mode 'scheme-mode)) + ;; In `scheme-mode' we must check the current Scheme implementation + ;; being used + (and (boundp 'geiser-impl--implementation) + (eq geiser-impl--implementation 'racket))) + (flycheck-racket-has-expand-p 'racket))) + :verify + (lambda (checker) + (let ((has-expand (flycheck-racket-has-expand-p checker)) + (in-scheme-mode (eq major-mode 'scheme-mode)) + (geiser-impl (bound-and-true-p geiser-impl--implementation))) + (list + (flycheck-verification-result-new + :label "compiler-lib package" + :message (if has-expand "present" "missing") + :face (if has-expand 'success '(bold error))) + (flycheck-verification-result-new + :label "Geiser Implementation" + :message (cond + ((not in-scheme-mode) "Using Racket Mode") + ((eq geiser-impl 'racket) "Racket") + (geiser-impl (format "Other: %s" geiser-impl)) + (t "Geiser not active")) + :face (cond + ((or (not in-scheme-mode) (eq geiser-impl 'racket)) 'success) + (t '(bold error))))))) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-increment-error-columns + (seq-remove + (lambda (err) + (string-suffix-p + "/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt" + (flycheck-error-filename err))) + errors)))) + :error-patterns + ((error line-start (zero-or-more space) + (file-name) ":" line ":" column ":" (message) line-end)) + :modes (racket-mode scheme-mode)) + +(flycheck-define-checker rpm-rpmlint + "A RPM SPEC file syntax checker using rpmlint. + +See URL `https://github.com/rpm-software-management/rpmlint'." + :command ("rpmlint" source) + :error-patterns + ((error line-start + (file-name) ":" (optional line ":") " E: " (message) + line-end) + (warning line-start + (file-name) ":" (optional line ":") " W: " (message) + line-end)) + :error-filter + ;; rpmlint 1.1 outputs a spurious error for the temp file created by flycheck + (lambda (errors) + (dolist (err (seq-remove + (lambda (err) + (string-suffix-p "(none)" (flycheck-error-filename err))) + errors)) + ;; Add fake line numbers if they are missing in the lint output + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 1))) + errors) + :error-explainer + (lambda (error) + (-when-let* ((error-message (flycheck-error-message error)) + (message-id (save-match-data + (string-match "\\([^ ]+\\)" error-message) + (match-string 1 error-message)))) + (flycheck-call-checker-process-for-output + 'rpm-rpmlint nil t "-I" message-id))) + :modes (sh-mode rpm-spec-mode) + :predicate (lambda () (or (not (eq major-mode 'sh-mode)) + ;; In `sh-mode', we need the proper shell + (eq sh-shell 'rpm)))) + +(flycheck-def-config-file-var flycheck-markdown-markdownlint-cli-config + markdown-markdownlint-cli nil + :package-version '(flycheck . "32")) + +(flycheck-define-checker markdown-markdownlint-cli + "Markdown checker using markdownlint-cli. + +See URL `https://github.com/igorshubovych/markdownlint-cli'." + :command ("markdownlint" + (config-file "--config" flycheck-markdown-markdownlint-cli-config) + source) + :error-patterns + ((error line-start + (file-name) ":" line + (? ":" column) " " (id (one-or-more (not (any space)))) + " " (message) line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "(string)" errors))) + :modes (markdown-mode gfm-mode)) + +(flycheck-def-option-var flycheck-markdown-mdl-rules nil markdown-mdl + "Rules to enable for mdl. + +The value of this variable is a list of strings each of which is +the name of a rule to enable. + +By default all rules are enabled. + +See URL `https://git.io/vhi2t'." + :type '(repeat :tag "Enabled rules" + (string :tag "rule name")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "27")) + +(flycheck-def-option-var flycheck-markdown-mdl-tags nil markdown-mdl + "Rule tags to enable for mdl. + +The value of this variable is a list of strings each of which is +the name of a rule tag. Only rules with these tags are enabled. + +By default all rules are enabled. + +See URL `https://git.io/vhi2t'." + :type '(repeat :tag "Enabled tags" + (string :tag "tag name")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "27")) + +(flycheck-def-config-file-var flycheck-markdown-mdl-style markdown-mdl nil + :package-version '(flycheck . "27")) + +(flycheck-define-checker markdown-mdl + "Markdown checker using mdl. + +See URL `https://github.com/markdownlint/markdownlint'." + :command ("mdl" + (config-file "--style" flycheck-markdown-mdl-style) + (option "--tags=" flycheck-markdown-mdl-rules concat + flycheck-option-comma-separated-list) + (option "--rules=" flycheck-markdown-mdl-rules concat + flycheck-option-comma-separated-list)) + :standard-input t + :error-patterns + ((error line-start + (file-name) ":" line ": " (id (one-or-more alnum)) " " (message) + line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "(stdin)" errors))) + :modes (markdown-mode gfm-mode)) + +(flycheck-define-checker nix + "Nix checker using nix-instantiate. + +See URL `https://nixos.org/nix/manual/#sec-nix-instantiate'." + :command ("nix-instantiate" "--parse" "-") + :standard-input t + :error-patterns + ((error line-start + "at: (" line ":" column ") from stdin" + (one-or-more "\n" (zero-or-more space (one-or-more not-newline))) + (message) line-end) + (error line-start + "error: " (message) " at " (file-name) ":" line ":" column + line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "(string)" errors))) + :next-checkers ((warning . nix-linter)) + :modes nix-mode) + +(defun flycheck-parse-nix-linter (output checker buffer) + "Parse nix-linter warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://github.com/Synthetica9/nix-linter' for more +information about nix-linter." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at + .pos.spanBegin.sourceLine + .pos.spanBegin.sourceColumn + 'warning + .description + :id .offense + :checker checker + :buffer buffer + :filename (buffer-file-name buffer) + :end-line .pos.spanEnd.sourceLine + :end-column .pos.spanEnd.sourceColumn))) + (flycheck-parse-json output))) + +(flycheck-define-checker nix-linter + "Nix checker using nix-linter. + +See URL `https://github.com/Synthetica9/nix-linter'." + :command ("nix-linter" "--json-stream" "-") + :standard-input t + :error-parser flycheck-parse-nix-linter + :error-explainer + (lambda (error) + (-when-let (error-code (flycheck-error-id error)) + (flycheck-call-checker-process-for-output + 'nix-linter nil t "--help-for" error-code))) + :modes nix-mode) + +(defun flycheck-locate-sphinx-source-directory () + "Locate the Sphinx source directory for the current buffer. + +Return the source directory, or nil, if the current buffer is not +part of a Sphinx project." + (-when-let* ((filename (buffer-file-name)) + (dir (locate-dominating-file filename "conf.py"))) + (expand-file-name dir))) + +(flycheck-define-checker rst + "A ReStructuredText (RST) syntax checker using Docutils. + +See URL `http://docutils.sourceforge.net/'." + ;; include:: directives + :command ("rst2pseudoxml.py" "--report=2" "--halt=5" + ;; Read from standard input and throw output away + "-" null-device) + :standard-input t + :error-patterns + ((warning line-start ":" line ": (WARNING/2) " (message) line-end) + (error line-start ":" line + ": (" (or "ERROR/3" "SEVERE/4") ") " + (message) line-end)) + :modes rst-mode) + +(flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx + "Whether to warn about missing references in Sphinx. + +When non-nil (the default), warn about all missing references in +Sphinx via `-n'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.17")) + +(flycheck-define-checker rst-sphinx + "A ReStructuredText (RST) syntax checker using Sphinx. + +Requires Sphinx 1.2 or newer. See URL `http://sphinx-doc.org'." + :command ("sphinx-build" "-b" "pseudoxml" + "-q" "-N" ; Reduced output and no colors + (option-flag "-n" flycheck-sphinx-warn-on-missing-references) + (eval (flycheck-locate-sphinx-source-directory)) + temporary-directory ; Redirect the output to a temporary + ; directory + source-original) ; Sphinx needs the original document + :error-patterns + ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end) + (error line-start + (file-name) ":" line + ": " (or "ERROR" "SEVERE") ": " + (message) line-end)) + :modes rst-mode + :predicate (lambda () (and (flycheck-buffer-saved-p) + (flycheck-locate-sphinx-source-directory)))) + +(defun flycheck-ruby--find-project-root (_checker) + "Compute an appropriate working-directory for flycheck-ruby. + +This is either a parent directory containing a Gemfile, or nil." + (and + buffer-file-name + (locate-dominating-file buffer-file-name "Gemfile"))) + +(flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml") + +(flycheck-def-option-var flycheck-rubocop-lint-only nil + (ruby-rubocop ruby-standard) + "Whether to only report code issues in Rubocop and Standard. + +When non-nil, only report code issues, via `--lint'. Otherwise +report style issues as well." + :safe #'booleanp + :type 'boolean + :package-version '(flycheck . "0.16")) + +(defconst flycheck-ruby-rubocop-error-patterns + '((info line-start (file-name) ":" line ":" column ": C: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end) + (warning line-start (file-name) ":" line ":" column ": W: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end) + (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end))) + +(flycheck-def-executable-var ruby-rubocop "rubocop") +(flycheck-define-command-checker 'ruby-rubocop + "A Ruby syntax and style checker using the RuboCop tool. + +You need at least RuboCop 0.34 for this syntax checker. + +See URL `https://rubocop.org/'." + ;; ruby-standard is defined based on this checker + :command '("rubocop" + "--display-cop-names" + "--force-exclusion" + "--format" "emacs" + ;; Explicitly disable caching to prevent Rubocop 0.35.1 and earlier + ;; from caching standard input. Later versions of Rubocop + ;; automatically disable caching with --stdin, see + ;; https://github.com/flycheck/flycheck/issues/844 and + ;; https://github.com/bbatsov/rubocop/issues/2576 + "--cache" "false" + (config-file "--config" flycheck-rubocoprc) + (option-flag "--lint" flycheck-rubocop-lint-only) + ;; Rubocop takes the original file name as argument when reading + ;; from standard input + "--stdin" source-original) + :standard-input t + :working-directory #'flycheck-ruby--find-project-root + :error-patterns flycheck-ruby-rubocop-error-patterns + :modes '(enh-ruby-mode ruby-mode) + :next-checkers '((warning . ruby-reek) + (warning . ruby-rubylint))) + +(flycheck-def-config-file-var flycheck-ruby-standardrc ruby-standard + ".standard.yml") + +(flycheck-def-executable-var ruby-standard "standardrb") +(flycheck-define-command-checker 'ruby-standard + "A Ruby syntax and style checker using the StandardRB gem. + +See URL `https://github.com/testdouble/standard' for more information." + ;; This checker is derived from ruby-rubocop; see above + :command '("standardrb" + "--display-cop-names" + "--force-exclusion" + "--format" "emacs" + "--cache" "false" + (config-file "--config" flycheck-ruby-standardrc) + (option-flag "--lint" flycheck-rubocop-lint-only) + "--stdin" source-original) + :standard-input t + :working-directory #'flycheck-ruby--find-project-root + :error-patterns flycheck-ruby-rubocop-error-patterns + :modes '(enh-ruby-mode ruby-mode) + :next-checkers '((warning . ruby-reek) + (warning . ruby-rubylint))) + +(flycheck-def-config-file-var flycheck-reekrc ruby-reek ".reek.yml" + :safe #'string-or-null-p + :package-version '(flycheck . "30")) + +(flycheck-define-checker ruby-reek + "A Ruby smell checker using reek. + +See URL `https://github.com/troessner/reek'." + :command ("reek" "--format" "json" + (config-file "--config" flycheck-reekrc) + source) + :error-parser flycheck-parse-reek + :modes (enh-ruby-mode ruby-mode) + :next-checkers ((warning . ruby-rubylint))) + +;; Default to `nil' to let Rubylint find its configuration file by itself, and +;; to maintain backwards compatibility with older Rubylint and Flycheck releases +(flycheck-def-config-file-var flycheck-rubylintrc ruby-rubylint nil) + +(flycheck-define-checker ruby-rubylint + "A Ruby syntax and code analysis checker using ruby-lint. + +Requires ruby-lint 2.0.2 or newer. See URL +`https://github.com/YorickPeterse/ruby-lint'." + :command ("ruby-lint" "--presenter=syntastic" + (config-file "--config" flycheck-rubylintrc) + source) + ;; Ruby Lint can't read from standard input + :error-patterns + ((info line-start + (file-name) ":I:" line ":" column ": " (message) line-end) + (warning line-start + (file-name) ":W:" line ":" column ": " (message) line-end) + (error line-start + (file-name) ":E:" line ":" column ": " (message) line-end)) + :modes (enh-ruby-mode ruby-mode)) + +(flycheck-define-checker ruby + "A Ruby syntax checker using the standard Ruby interpreter. + +Please note that the output of different Ruby versions and +implementations varies wildly. This syntax checker supports +current versions of MRI and JRuby, but may break when used with +other implementations or future versions of these +implementations. + +Please consider using `ruby-rubocop' or `ruby-reek' instead. + +See URL `https://www.ruby-lang.org/'." + :command ("ruby" "-w" "-c") + :standard-input t + :error-patterns + ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv + ((error line-start "SyntaxError in -:" line ": " (message) line-end) + (warning line-start "-:" line ":" (optional column ":") + " warning: " (message) line-end) + (error line-start "-:" line ": " (message) line-end)) + :modes (enh-ruby-mode ruby-mode) + :next-checkers ((warning . ruby-rubylint))) + +(flycheck-define-checker ruby-jruby + "A Ruby syntax checker using the JRuby interpreter. + +This syntax checker is very primitive, and may break on future +versions of JRuby. + +Please consider using `ruby-rubocop' or `ruby-rubylint' instead. + +See URL `http://jruby.org/'." + :command ("jruby" "-w" "-c") + :standard-input t + :error-patterns + ((error line-start "SyntaxError in -:" line ": " (message) line-end) + (warning line-start "-:" line ": warning: " (message) line-end) + (error line-start "-:" line ": " (message) line-end)) + :modes (enh-ruby-mode ruby-mode) + :next-checkers ((warning . ruby-rubylint))) + +(flycheck-def-args-var flycheck-cargo-check-args (rust-cargo) + :package-version '(flycheck . "32")) + +(flycheck-def-args-var flycheck-rust-args (rust) + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust) + "Whether to check test code in Rust. + +For the `rust' checker: When non-nil, `rustc' is passed the +`--test' flag, which will check any code marked with the +`#[cfg(test)]' attribute and any functions marked with +`#[test]'. Otherwise, `rustc' is not passed `--test' and test +code will not be checked. Skipping `--test' is necessary when +using `#![no_std]', because compiling the test runner requires +`std'. + +For the `rust-cargo' checker: When non-nil, calls `cargo test +--no-run' instead of `cargo check'." + :type 'boolean + :safe #'booleanp + :package-version '("flycheck" . "0.19")) + +(flycheck-def-option-var flycheck-rust-crate-root nil rust + "A path to the crate root for the current buffer. + +The value of this variable is either a string with the path to +the crate root for the current buffer, or nil if the current buffer +is a crate. A relative path is relative to the current buffer. + +If this variable is non nil the current buffer will only be checked +if it is not modified, i.e. after it has been saved." + :type '(choice (const :tag "Unspecified" nil) + (file :tag "Root")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.20")) +(make-variable-buffer-local 'flycheck-rust-crate-root) + +(flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust) + "The type of the Rust Crate to check. + +For `rust-cargo', the value should be a string denoting the +target type passed to Cargo. See +`flycheck-rust-valid-crate-type-p' for the list of allowed +values. + +For `rust', the value should be a string denoting the crate type +for the `--crate-type' flag of rustc." + :type '(choice (const :tag "nil (rust/rust-cargo)" nil) + (const :tag "lib (rust/rust-cargo)" "lib") + (const :tag "bin (rust/rust-cargo)" "bin") + (const :tag "example (rust-cargo)" "example") + (const :tag "test (rust-cargo)" "test") + (const :tag "bench (rust-cargo)" "bench") + (const :tag "rlib (rust)" "rlib") + (const :tag "dylib (rust)" "dylib") + (const :tag "cdylib (rust)" "cdylib") + (const :tag "staticlib (rust)" "staticlib") + (const :tag "metadata (rust)" "metadata")) + :safe #'stringp + :package-version '(flycheck . "0.20")) +(make-variable-buffer-local 'flycheck-rust-crate-type) + +(flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo + "The name of the binary to pass to `cargo check --CRATE-TYPE'. + +The value of this variable is a string denoting the name of the +target to check: usually the name of the crate, or the name of +one of the files under `src/bin', `tests', `examples' or +`benches'. + +This always requires a non-nil value, unless +`flycheck-rust-crate-type' is `lib' or nil, in which case it is +ignored." + :type '(choice (const :tag "Unspecified" nil) + (string :tag "Binary name")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "28")) +(make-variable-buffer-local 'flycheck-rust-binary-name) + +(flycheck-def-option-var flycheck-rust-features nil rust-cargo + "List of features to activate during build or check. + +The value of this variable is a list of strings denoting features +that will be activated to build the target to check. Features will +be passed to `cargo check --features=FEATURES'." + :type '(repeat :tag "Features to activate" + (string :tag "Feature")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-rust-features) + +(flycheck-def-option-var flycheck-rust-library-path nil rust + "A list of library directories for Rust. + +The value of this variable is a list of strings, where each +string is a directory to add to the library path of Rust. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Library directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.18")) + +(defun flycheck--fontify-as-markdown () + "Place current buffer in `markdown-view-mode' and fontify it." + (when (fboundp 'markdown-view-mode) + (let ((markdown-fontify-code-block-default-mode 'rust-mode) + (markdown-fontify-code-blocks-natively t) + (markdown-hide-markup t)) + (markdown-view-mode) + (font-lock-flush) + (font-lock-ensure)))) + +(defun flycheck-rust-error-explainer (error) + "Return an explanation for the given `flycheck-error' ERROR." + (-when-let (error-code (flycheck-error-id error)) + (lambda () + (flycheck-call-checker-process + 'rust nil standard-output t "--explain" error-code) + (with-current-buffer standard-output + (flycheck--fontify-as-markdown))))) + +(defun flycheck-rust-error-filter (errors) + "Filter ERRORS from rustc output that have no explanatory value." + (seq-remove + (lambda (err) + (or + ;; Macro errors emit a diagnostic in a phony file, + ;; e.g. "". + (-when-let (filename (flycheck-error-filename err)) + (string-match-p (rx "macros>" line-end) filename)) + ;; Redundant message giving the number of failed errors + (-when-let (msg (flycheck-error-message err)) + (string-match-p + (rx + (or (: "aborting due to " (optional (one-or-more num) " ") + "previous error") + (: "For more information about this error, try `rustc --explain " + (one-or-more alnum) "`."))) + msg)))) + errors)) + +(defun flycheck-rust-manifest-directory () + "Return the nearest directory holding the Cargo manifest. + +Return the nearest directory containing the `Cargo.toml' manifest +file, starting from the current buffer and using +`locate-dominating-file'. Return nil if there is no such file, +or if the current buffer has no file name." + (and buffer-file-name + (locate-dominating-file buffer-file-name "Cargo.toml"))) + +(defun flycheck-rust-cargo-metadata () + "Run 'cargo metadata' and return the result as parsed JSON object." + (car (flycheck-parse-json + (flycheck-call-checker-process-for-output + 'rust-cargo nil t + "metadata" "--no-deps" "--format-version" "1")))) + +(defun flycheck-rust-cargo-workspace-root () + "Return the path to the workspace root of a Rust Cargo project. + +Return nil if the workspace root does not exist (for Rust +versions inferior to 1.25)." + (let-alist (flycheck-rust-cargo-metadata) + .workspace_root)) + +(defun flycheck-rust-cargo-has-command-p (command) + "Whether Cargo has COMMAND in its list of commands. + +Execute `cargo --list' to find out whether COMMAND is present." + (let ((cargo (funcall flycheck-executable-find "cargo"))) + (member command (mapcar #'string-trim-left + (ignore-errors (process-lines cargo "--list")))))) + +(defun flycheck-rust-valid-crate-type-p (crate-type) + "Whether CRATE-TYPE is a valid target type for Cargo. + +A valid Cargo target type is one of `lib', `bin', `example', +`test' or `bench'." + (member crate-type '(nil "lib" "bin" "example" "test" "bench"))) + +(flycheck-define-checker rust-cargo + "A Rust syntax checker using Cargo. + +This syntax checker requires Rust 1.17 or newer. See URL +`https://www.rust-lang.org'." + :command ("cargo" + (eval (if flycheck-rust-check-tests + "test" + "check")) + (eval (when flycheck-rust-check-tests + "--no-run")) + (eval (when flycheck-rust-crate-type + (concat "--" flycheck-rust-crate-type))) + ;; All crate targets except "lib" need a binary name + (eval (when (and flycheck-rust-crate-type + (not (string= flycheck-rust-crate-type "lib"))) + flycheck-rust-binary-name)) + (option "--features=" flycheck-rust-features concat + flycheck-option-comma-separated-list) + (eval flycheck-cargo-check-args) + "--message-format=json") + :error-parser flycheck-parse-cargo-rustc + :error-filter (lambda (errors) + ;; In Rust 1.25+, filenames are relative to the workspace + ;; root. + (let ((root (flycheck-rust-cargo-workspace-root))) + (seq-do (lambda (err) + ;; Some errors are crate level and do not have a + ;; filename + (when (flycheck-error-filename err) + (setf (flycheck-error-filename err) + (expand-file-name + (flycheck-error-filename err) root)))) + (flycheck-rust-error-filter errors)))) + :error-explainer flycheck-rust-error-explainer + :modes rust-mode + :predicate flycheck-buffer-saved-p + :enabled flycheck-rust-manifest-directory + :working-directory (lambda (_) (flycheck-rust-manifest-directory)) + :verify + (lambda (_) + (and buffer-file-name + (let* ((has-toml (flycheck-rust-manifest-directory)) + (valid-crate-type (flycheck-rust-valid-crate-type-p + flycheck-rust-crate-type)) + (need-binary-name + (and flycheck-rust-crate-type + (not (string= flycheck-rust-crate-type "lib"))))) + (list + (flycheck-verification-result-new + :label "Cargo.toml" + :message (if has-toml "Found" "Missing") + :face (if has-toml 'success '(bold warning))) + (flycheck-verification-result-new + :label "Crate type" + :message (if valid-crate-type + (format "%s" flycheck-rust-crate-type) + (format "%s (invalid, should be one of 'lib', 'bin', \ +'test', 'example' or 'bench')" + flycheck-rust-crate-type)) + :face (if valid-crate-type 'success '(bold error))) + (flycheck-verification-result-new + :label "Binary name" + :message (cond + ((not need-binary-name) "Not required") + ((not flycheck-rust-binary-name) "Required") + (t (format "%s" flycheck-rust-binary-name))) + :face (cond + ((not need-binary-name) 'success) + ((not flycheck-rust-binary-name) '(bold error)) + (t 'success)))))))) + +(flycheck-define-checker rust + "A Rust syntax checker using Rust compiler. + +This syntax checker needs Rust 1.18 or newer. See URL +`https://www.rust-lang.org'." + :command ("rustc" + (option "--crate-type" flycheck-rust-crate-type) + "--emit=mir" "-o" "/dev/null" ; avoid creating binaries + "--error-format=json" + (option-flag "--test" flycheck-rust-check-tests) + (option-list "-L" flycheck-rust-library-path concat) + (eval flycheck-rust-args) + (eval (or flycheck-rust-crate-root + (flycheck-substitute-argument 'source-original 'rust)))) + :error-parser flycheck-parse-rustc + :error-filter flycheck-rust-error-filter + :error-explainer flycheck-rust-error-explainer + :modes rust-mode + :predicate flycheck-buffer-saved-p) + +(flycheck-define-checker rust-clippy + "A Rust syntax checker using clippy. + +See URL `https://github.com/rust-lang-nursery/rust-clippy'." + :command ("cargo" "clippy" "--message-format=json") + :error-parser flycheck-parse-cargo-rustc + :error-filter flycheck-rust-error-filter + :error-explainer flycheck-rust-error-explainer + :modes rust-mode + :predicate flycheck-buffer-saved-p + :enabled (lambda () + (and (flycheck-rust-cargo-has-command-p "clippy") + (flycheck-rust-manifest-directory))) + :working-directory (lambda (_) (flycheck-rust-manifest-directory)) + :verify + (lambda (_) + (and buffer-file-name + (let ((has-toml (flycheck-rust-manifest-directory)) + (has-clippy (flycheck-rust-cargo-has-command-p "clippy"))) + (list + (flycheck-verification-result-new + :label "Clippy" + :message (if has-clippy "Found" + "Cannot find the `cargo clippy' command") + :face (if has-clippy 'success '(bold warning))) + (flycheck-verification-result-new + :label "Cargo.toml" + :message (if has-toml "Found" "Missing") + :face (if has-toml 'success '(bold warning)))))))) + +(defvar flycheck-sass-scss-cache-directory nil + "The cache directory for `sass' and `scss'.") + +(defun flycheck-sass-scss-cache-location () + "Get the cache location for `sass' and `scss'. + +If no cache directory exists yet, create one and return it. +Otherwise return the previously used cache directory." + (setq flycheck-sass-scss-cache-directory + (or flycheck-sass-scss-cache-directory + (make-temp-file "flycheck-sass-scss-cache" 'directory)))) + +(flycheck-def-option-var flycheck-sass-compass nil sass + "Whether to enable the Compass CSS framework. + +When non-nil, enable the Compass CSS framework, via `--compass'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-define-checker sass + "A Sass syntax checker using the Sass compiler. + +See URL `http://sass-lang.com'." + :command ("sass" + "--cache-location" (eval (flycheck-sass-scss-cache-location)) + (option-flag "--compass" flycheck-sass-compass) + "--check" "--stdin") + :standard-input t + :error-patterns + ((error line-start + (or "Syntax error: " "Error: ") + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + (optional "\r") "\n" (one-or-more " ") "on line " line + " of standard input" + line-end) + (warning line-start + "WARNING: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + (optional "\r") "\n" (one-or-more " ") "on line " line + " of " (one-or-more not-newline) + line-end)) + :modes sass-mode) + +(flycheck-def-config-file-var flycheck-sass-lintrc sass/scss-sass-lint + ".sass-lint.yml" + :package-version '(flycheck . "30")) + +(flycheck-define-checker sass/scss-sass-lint + "A SASS/SCSS syntax checker using sass-Lint. + +See URL `https://github.com/sasstools/sass-lint'." + :command ("sass-lint" + "--verbose" + "--no-exit" + "--format" "Checkstyle" + (config-file "--config" flycheck-sass-lintrc) + source) + :error-parser flycheck-parse-checkstyle + :modes (sass-mode scss-mode)) + +(flycheck-define-checker scala + "A Scala syntax checker using the Scala compiler. + +See URL `https://www.scala-lang.org/'." + :command ("scalac" "-Ystop-after:parser" source) + :error-patterns + ((error line-start (file-name) ":" line ": error: " (message) line-end)) + :modes scala-mode + :next-checkers ((warning . scala-scalastyle))) + +(flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker scala-scalastyle + "A Scala style checker using scalastyle. + +Note that this syntax checker is not used if +`flycheck-scalastylerc' is nil or refers to a non-existing file. + +See URL `http://www.scalastyle.org'." + :command ("scalastyle" + (config-file "-c" flycheck-scalastylerc) + source) + :error-patterns + ((error line-start "error file=" (file-name) " message=" + (message) " line=" line (optional " column=" column) line-end) + (warning line-start "warning file=" (file-name) " message=" + (message) " line=" line (optional " column=" column) line-end)) + :error-filter (lambda (errors) + (flycheck-sanitize-errors + (flycheck-increment-error-columns errors))) + :modes scala-mode + :predicate + ;; Inhibit this syntax checker if the JAR or the configuration are unset or + ;; missing + (lambda () (and flycheck-scalastylerc + (flycheck-locate-config-file flycheck-scalastylerc + 'scala-scalastyle))) + :verify (lambda (checker) + (let ((config-file (and flycheck-scalastylerc + (flycheck-locate-config-file + flycheck-scalastylerc checker)))) + (list + (flycheck-verification-result-new + :label "Configuration file" + :message (cond + ((not flycheck-scalastylerc) + "`flycheck-scalastyletrc' not set") + ((not config-file) + (format "file %s not found" flycheck-scalastylerc)) + (t (format "found at %s" config-file))) + :face (cond + ((not flycheck-scalastylerc) '(bold warning)) + ((not config-file) '(bold error)) + (t 'success))))))) + +(flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken + :package-version '(flycheck . "32")) + +(flycheck-define-checker scheme-chicken + "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'. + +See URL `http://call-cc.org/'." + :command ("csc" "-analyze-only" "-local" + (eval flycheck-scheme-chicken-args) + source) + :error-patterns + ((info line-start + "Note: " (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + (warning line-start + "Warning: " (zero-or-more not-newline) ",\n" + (one-or-more (any space)) (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + (warning line-start + "Warning: " (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + (error line-start "Error: (line " line ") " (message) line-end) + (error line-start "Syntax error: (" (file-name) ":" line ")" + (zero-or-more not-newline) " - " + (message (one-or-more not-newline) + (zero-or-more "\n" + (zero-or-more space) + (zero-or-more not-newline)) + (one-or-more space) "<--") + line-end) + ;; A of version 4.12.0, the chicken compiler doesn't provide a + ;; line number for this error. + (error line-start "Syntax error: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (zero-or-more space) + (zero-or-more not-newline)) + (one-or-more space) "<--") + line-end) + (error line-start + "Error: " (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + ;; A of version 4.12.0, the chicken compiler doesn't provide a + ;; line number for this error. + (error line-start "Error: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (zero-or-more space) + (zero-or-more not-newline)) + (one-or-more space) "<--"))) + :error-filter flycheck-fill-empty-line-numbers + :predicate + (lambda () + ;; In `scheme-mode' we must check the current Scheme implementation + ;; being used + (and (boundp 'geiser-impl--implementation) + (eq geiser-impl--implementation 'chicken))) + :verify + (lambda (_checker) + (let ((geiser-impl (bound-and-true-p geiser-impl--implementation))) + (list + (flycheck-verification-result-new + :label "Geiser Implementation" + :message (cond + ((eq geiser-impl 'chicken) "Chicken Scheme") + (geiser-impl (format "Other: %s" geiser-impl)) + (t "Geiser not active")) + :face (cond + ((eq geiser-impl 'chicken) 'success) + (t '(bold error))))))) + :modes scheme-mode) + +(defconst flycheck-scss-lint-checkstyle-re + (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle") + "Regular expression to parse missing checkstyle error.") + +(defun flycheck-parse-scss-lint (output checker buffer) + "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER. + +Like `flycheck-parse-checkstyle', but catches errors about +missing checkstyle reporter from SCSS-Lint." + (if (string-match-p flycheck-scss-lint-checkstyle-re output) + (list (flycheck-error-new-at + 1 nil 'error "Checkstyle reporter for SCSS-Lint missing. +Please run gem install scss_lint_reporter_checkstyle" + :checker checker + :buffer buffer + :filename (buffer-file-name buffer))) + (flycheck-parse-checkstyle output checker buffer))) + +(flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml" + :package-version '(flycheck . "0.23")) + +(flycheck-define-checker scss-lint + "A SCSS syntax checker using SCSS-Lint. + +Needs SCSS-Lint 0.43.2 or newer. + +See URL `https://github.com/brigade/scss-lint'." + :command ("scss-lint" + "--require=scss_lint_reporter_checkstyle" + "--format=Checkstyle" + (config-file "--config" flycheck-scss-lintrc) + "--stdin-file-path" source-original "-") + :standard-input t + ;; We cannot directly parse Checkstyle XML, since for some mysterious reason + ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it + ;; as an addon which might not be installed. We use a custom error parser to + ;; check whether the addon is missing and turn that into a special kind of + ;; Flycheck error. + :error-parser flycheck-parse-scss-lint + :modes scss-mode + :verify + (lambda (checker) + (-when-let + (output (flycheck-call-checker-process-for-output + checker nil nil "--require=scss_lint_reporter_checkstyle")) + (let ((reporter-missing + (string-match-p flycheck-scss-lint-checkstyle-re output))) + (list + (flycheck-verification-result-new + :label "checkstyle reporter" + :message (if reporter-missing + "scss_lint_reporter_checkstyle plugin missing" + "present") + :face (if reporter-missing + '(bold error) + 'success))))))) + +(flycheck-define-checker scss-stylelint + "A SCSS syntax and style checker using stylelint. + +See URL `http://stylelint.io/'." + :command ("stylelint" + (eval flycheck-stylelint-args) + "--syntax" "scss" + (option-flag "--quiet" flycheck-stylelint-quiet) + (config-file "--config" flycheck-stylelintrc)) + :standard-input t + :error-parser flycheck-parse-stylelint + :predicate flycheck-buffer-nonempty-p + :modes (scss-mode)) + +(flycheck-def-option-var flycheck-scss-compass nil scss + "Whether to enable the Compass CSS framework. + +When non-nil, enable the Compass CSS framework, via `--compass'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-define-checker scss + "A SCSS syntax checker using the SCSS compiler. + +See URL `http://sass-lang.com'." + :command ("scss" + "--cache-location" (eval (flycheck-sass-scss-cache-location)) + (option-flag "--compass" flycheck-scss-compass) + "--check" "--stdin") + :standard-input t + :error-patterns + ((error line-start + (or "Syntax error: " "Error: ") + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + (optional "\r") "\n" (one-or-more " ") "on line " line + " of standard input" + line-end) + (warning line-start + "WARNING: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + (optional "\r") "\n" (one-or-more " ") "on line " line + " of an unknown file" + line-end)) + :modes scss-mode) + +(flycheck-def-args-var flycheck-sh-bash-args (sh-bash) + :package-version '(flycheck . "32")) + +(flycheck-define-checker sh-bash + "A Bash syntax checker using the Bash shell. + +See URL `http://www.gnu.org/software/bash/'." + :command ("bash" "--norc" "-n" + (eval flycheck-sh-bash-args) + "--") + :standard-input t + :error-patterns + ((error line-start + ;; The name/path of the bash executable + (one-or-more (not (any ":"))) ":" + ;; A label "line", possibly localized + (one-or-more (not (any digit))) + line (zero-or-more " ") ":" (zero-or-more " ") + (message) line-end)) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'bash)) + :next-checkers ((warning . sh-shellcheck))) + +(flycheck-define-checker sh-posix-dash + "A POSIX Shell syntax checker using the Dash shell. + +See URL `http://gondor.apana.org.au/~herbert/dash/'." + :command ("dash" "-n") + :standard-input t + :error-patterns + ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message))) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'sh)) + :next-checkers ((warning . sh-shellcheck))) + +(flycheck-define-checker sh-posix-bash + "A POSIX Shell syntax checker using the Bash shell. + +See URL `http://www.gnu.org/software/bash/'." + :command ("bash" "--posix" "--norc" "-n" "--") + :standard-input t + :error-patterns + ((error line-start + ;; The name/path of the bash executable + (one-or-more (not (any ":"))) ":" + ;; A label "line", possibly localized + (one-or-more (not (any digit))) + line (zero-or-more " ") ":" (zero-or-more " ") + (message) line-end)) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'sh)) + :next-checkers ((warning . sh-shellcheck))) + +(flycheck-define-checker sh-zsh + "A Zsh syntax checker using the Zsh shell. + +See URL `http://www.zsh.org/'." + :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source) + :error-patterns + ((error line-start (file-name) ":" line ": " (message) line-end)) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'zsh)) + :next-checkers ((warning . sh-shellcheck))) + +(defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh) + "Shells supported by ShellCheck.") + +(flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck + "A list of excluded warnings for ShellCheck. + +The value of this variable is a list of strings, where each +string is a warning code to be excluded from ShellCheck reports. +By default, no warnings are excluded." + :type '(repeat :tag "Excluded warnings" + (string :tag "Warning code")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.21")) + +(flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck + "Whether to follow external sourced files in scripts. + +Shellcheck will follow and parse sourced files so long as a +pre-runtime resolvable path to the file is present. This can +either be part of the source command itself: + source /full/path/to/file.txt +or added as a shellcheck directive before the source command: + # shellcheck source=/full/path/to/file.txt." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "31")) + +(flycheck-define-checker sh-shellcheck + "A shell script syntax and style checker using Shellcheck. + +See URL `https://github.com/koalaman/shellcheck/'." + :command ("shellcheck" + "--format" "checkstyle" + "--shell" (eval (symbol-name sh-shell)) + (option-flag "--external-sources" + flycheck-shellcheck-follow-sources) + (option "--exclude" flycheck-shellcheck-excluded-warnings list + flycheck-option-comma-separated-list) + "-") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter + (lambda (errors) + (flycheck-remove-error-file-names + "-" (flycheck-dequalify-error-ids errors))) + :modes sh-mode + :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells)) + :verify (lambda (_) + (let ((supports-shell (memq sh-shell + flycheck-shellcheck-supported-shells))) + (list + (flycheck-verification-result-new + :label (format "Shell %s supported" sh-shell) + :message (if supports-shell "yes" "no") + :face (if supports-shell 'success '(bold warning)))))) + :error-explainer + (lambda (err) + (let ((error-code (flycheck-error-id err)) + (url "https://github.com/koalaman/shellcheck/wiki/%s")) + (and error-code `(url . ,(format url error-code)))))) + +(flycheck-define-checker slim + "A Slim syntax checker using the Slim compiler. + +See URL `http://slim-lang.com'." + :command ("slimrb" "--compile") + :standard-input t + :error-patterns + ((error line-start + "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n " + "STDIN, Line " line (optional ", Column " column) + line-end)) + :modes slim-mode + :next-checkers ((warning . slim-lint))) + +(flycheck-define-checker slim-lint + "A Slim linter. + +See URL `https://github.com/sds/slim-lint'." + :command ("slim-lint" "--reporter=checkstyle" source) + :error-parser flycheck-parse-checkstyle + :modes slim-mode) + +(flycheck-define-checker sql-sqlint + "A SQL syntax checker using the sqlint tool. + +See URL `https://github.com/purcell/sqlint'." + :command ("sqlint") + :standard-input t + :error-patterns + ((warning line-start "stdin:" line ":" column ":WARNING " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + line-end) + (error line-start "stdin:" line ":" column ":ERROR " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + line-end)) + :modes (sql-mode)) + +(flycheck-define-checker systemd-analyze + "A systemd unit checker using systemd-analyze(1). + +See URL +`https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'." + :command ("systemd-analyze" "verify" source) + :error-parser flycheck-parse-with-patterns-without-color + :error-patterns + ((error line-start (file-name) ":" (optional line ":") (message) line-end) + (error line-start "[" (file-name) ":" line "]" (message) line-end)) + :error-filter (lambda (errors) + (flycheck-sanitize-errors + (flycheck-fill-empty-line-numbers errors))) + :modes (systemd-mode)) + +(flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc") + +(flycheck-define-checker tcl-nagelfar + "An extensible tcl syntax checker + +See URL `http://nagelfar.sourceforge.net/'." + :command ("nagelfar" "-H" source) + :error-patterns + ;; foo.tcl: 29: E Wrong number of arguments (4) to "set" + ;; foo.tcl: 29: W Expr without braces + ((info line-start (file-name) ": " line ": N " (message) line-end) + (warning line-start (file-name) ": " line ": W " (message) line-end) + (error line-start (file-name) ": " line ": E " (message) line-end)) + :modes tcl-mode) + +(flycheck-define-checker terraform + "A Terraform syntax checker with `terraform fmt'. + +See URL `https://www.terraform.io/docs/commands/fmt.html'." + :command ("terraform" "fmt" "-no-color" "-") + :standard-input t + :error-patterns + ((error line-start "Error: " (one-or-more not-newline) + "\n\n on line " line ", in " (one-or-more not-newline) ":" + (one-or-more "\n" (zero-or-more space (one-or-more not-newline))) + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end) + (error line-start "Error: " (one-or-more not-newline) + "\n\n on line " line ":\n (source code not available)\n\n" + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end)) + :next-checkers ((warning . terraform-tflint)) + :modes terraform-mode) + +(flycheck-def-option-var flycheck-tflint-variable-files nil terraform-tflint + "A list of files to resolve terraform variables. + +The value of this variable is a list of strings, where each +string is a file to add to the terraform variables files. +Relative files are relative to the file being checked." + :type '(repeat (directory :tag "Variable file")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(defun flycheck-parse-tflint-linter (output checker buffer) + "Parse tflint warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://github.com/wata727/tflint' for more +information about tflint." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at + .range.start.line + .range.start.column + (pcase .rule.severity + ("error" 'error) + ("warning" 'warning) + (_ 'error)) + .message + :end-line .range.end.line + :end-column .range.end.column + :id .rule.name + :checker checker + :buffer buffer + :filename (buffer-file-name buffer)))) + (cdr (assq 'issues (car (flycheck-parse-json output)))))) + +(flycheck-define-checker terraform-tflint + "A Terraform checker using tflint. + +See URL `https://github.com/wata727/tflint'." + :command ("tflint" "--format=json" + (option-list "--var-file=" flycheck-tflint-variable-files concat) + source-original) + :error-parser flycheck-parse-tflint-linter + :predicate flycheck-buffer-saved-p + :modes terraform-mode) + +(flycheck-define-checker tex-chktex + "A TeX and LaTeX syntax and style checker using chktex. + +See URL `http://www.nongnu.org/chktex/'." + :command ("chktex" + (config-file "--localrc" flycheck-chktexrc) + ;; Compact error messages, and no version information, and execute + ;; \input statements + "--verbosity=0" "--quiet" "--inputfiles") + :standard-input t + :error-patterns + ((warning line-start "stdin:" line ":" column ":" + (id (one-or-more digit)) ":" (message) line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors (flycheck-increment-error-columns errors))) + :modes (latex-mode plain-tex-mode)) + +(flycheck-define-checker tex-lacheck + "A LaTeX syntax and style checker using lacheck. + +See URL `http://www.ctan.org/pkg/lacheck'." + :command ("lacheck" source-inplace) + :error-patterns + ((warning line-start + "\"" (file-name) "\", line " line ": " (message) + line-end)) + :modes latex-mode) + +(flycheck-define-checker texinfo + "A Texinfo syntax checker using makeinfo. + +See URL `http://www.gnu.org/software/texinfo/'." + :command ("makeinfo" "-o" null-device "-") + :standard-input t + :error-patterns + ((warning line-start + "-:" line (optional ":" column) ": " "warning: " (message) + line-end) + (error line-start + "-:" line (optional ":" column) ": " (message) + line-end)) + :modes texinfo-mode) + +(flycheck-def-config-file-var flycheck-textlint-config + textlint "textlintrc.json") + +;; This needs to be set because textlint plugins are installed separately, +;; and there is no way to check their installation status -- textlint simply +;; prints a backtrace. +(flycheck-def-option-var flycheck-textlint-plugin-alist + '((markdown-mode . "@textlint/markdown") + (gfm-mode . "@textlint/markdown") + (t . "@textlint/text")) + textlint + "An alist mapping major modes to textlint plugins. + +Each item is a cons cell `(MAJOR-MODE . PLUGIN)', where MAJOR-MODE is a mode +`flycheck-textlint' supports and PLUGIN is a textlint plugin. As a catch-all, +when MAJOR-MODE is t, that PLUGIN will be used for any supported mode that +isn't specified. + +See URL `https://npms.io/search?q=textlint-plugin' for all textlint plugins +published on NPM." + :type '(repeat (choice (cons symbol string) + (cons (const t) string)))) + +(defun flycheck--textlint-get-plugin () + "Return the textlint plugin for the current mode." + (cdr (-first + (lambda (arg) + (pcase-let ((`(,mode . _) arg)) + (or (and (booleanp mode) mode) ; mode is t + (derived-mode-p mode)))) + flycheck-textlint-plugin-alist))) + +(flycheck-define-checker textlint + "A text prose linter using textlint. + +See URL `https://textlint.github.io/'." + :command ("textlint" + (config-file "--config" flycheck-textlint-config) + "--format" "json" + ;; get the first matching plugin from plugin-alist + "--plugin" + (eval (flycheck--textlint-get-plugin)) + source) + ;; textlint seems to say that its json output is compatible with ESLint. + ;; https://textlint.github.io/docs/formatter.html + :error-parser flycheck-parse-eslint + ;; textlint can support different formats with textlint plugins, but + ;; only text and markdown formats are installed by default. Ask the + ;; user to add mode->plugin mappings manually in + ;; `flycheck-textlint-plugin-alist'. + :modes + (text-mode markdown-mode gfm-mode message-mode adoc-mode + mhtml-mode latex-mode org-mode rst-mode) + :enabled + (lambda () (flycheck--textlint-get-plugin)) + :verify + (lambda (_) + (let ((plugin (flycheck--textlint-get-plugin))) + (list + (flycheck-verification-result-new + :label "textlint plugin" + :message plugin + :face 'success))))) + +(flycheck-def-config-file-var flycheck-typescript-tslint-config + typescript-tslint "tslint.json" + :package-version '(flycheck . "27")) + +(flycheck-def-option-var flycheck-typescript-tslint-rulesdir + nil typescript-tslint + "The directory of custom rules for TSLint. + +The value of this variable is either a string containing the path +to a directory with custom rules, or nil, to not give any custom +rules to TSLint. + +Refer to the TSLint manual at URL +`http://palantir.github.io/tslint/usage/cli/' +for more information about the custom directory." + :type '(choice (const :tag "No custom rules directory" nil) + (directory :tag "Custom rules directory")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "27")) + +(flycheck-def-args-var flycheck-tslint-args (typescript-tslint) + :package-version '(flycheck . "31")) + +(flycheck-define-checker typescript-tslint + "TypeScript style checker using TSLint. + +Note that this syntax checker is not used if +`flycheck-typescript-tslint-config' is nil or refers to a +non-existing file. + +See URL `https://github.com/palantir/tslint'." + :command ("tslint" "--format" "json" + (config-file "--config" flycheck-typescript-tslint-config) + (option "--rules-dir" flycheck-typescript-tslint-rulesdir) + (eval flycheck-tslint-args) + source-inplace) + :error-parser flycheck-parse-tslint + :modes (typescript-mode)) + +(flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator + "A list of include directories for Verilator. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of Verilator. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker verilog-verilator + "A Verilog syntax checker using the Verilator Verilog HDL simulator. + +See URL `https://www.veripool.org/wiki/verilator'." + :command ("verilator" "--lint-only" "-Wall" + (option-list "-I" flycheck-verilator-include-path concat) + source) + :error-patterns + ((warning line-start "%Warning-" (zero-or-more not-newline) ": " + (file-name) ":" line ": " (message) line-end) + (error line-start "%Error: " (file-name) ":" + line ": " (message) line-end)) + :modes verilog-mode) + +(flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl + "The language standard to use in GHDL. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `--std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-ghdl-language-standard) + +(flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl + "The directory to use for the file library. + +The value of this variable is either a string with the directory +to use for the file library, or nil, to use the default value. +When non-nil, pass the directory via the `--workdir' option." + :type '(choice (const :tag "Default directory" nil) + (string :tag "Directory for the file library")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-ghdl-workdir) + +(flycheck-def-option-var flycheck-ghdl-ieee-library nil vhdl-ghdl + "The standard to use for the IEEE library. + +The value of this variable is either a string denoting an ieee library +standard, or nil, to use the default standard. When non-nil, +pass the ieee library standard via the `--ieee' option." + :type '(choice (const :tag "Default standard" nil) + (const :tag "No IEEE Library" "none") + (const :tag "IEEE standard" "standard") + (const :tag "Synopsys standard" "synopsys") + (const :tag "Mentor standard" "mentor")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-ghdl-ieee-library) + +(flycheck-define-checker vhdl-ghdl + "A VHDL syntax checker using GHDL. + +See URL `https://github.com/ghdl/ghdl'." + :command ("ghdl" + "-s" ; only do the syntax checking + (option "--std=" flycheck-ghdl-language-standard concat) + (option "--workdir=" flycheck-ghdl-workdir concat) + (option "--ieee=" flycheck-ghdl-ieee-library concat) + source) + :error-patterns + ((error line-start (file-name) ":" line ":" column ": " (message) line-end)) + :modes vhdl-mode) + +(flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet + "An XSD schema to validate against." + :type '(choice (const :tag "None" nil) + (file :tag "XSD schema")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "31")) + +(flycheck-define-checker xml-xmlstarlet + "A XML syntax checker and validator using the xmlstarlet utility. + +See URL `http://xmlstar.sourceforge.net/'." + ;; Validate standard input with verbose error messages, and do not dump + ;; contents to standard output + :command ("xmlstarlet" "val" "--err" "--quiet" + (option "--xsd" flycheck-xml-xmlstarlet-xsd-path) + "-") + :standard-input t + :error-patterns + ((error line-start "-:" line "." column ": " (message) line-end)) + :modes (xml-mode nxml-mode)) + +(flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint + "An XSD schema to validate against." + :type '(choice (const :tag "None" nil) + (file :tag "XSD schema")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "31")) + +(flycheck-define-checker xml-xmllint + "A XML syntax checker and validator using the xmllint utility. + +The xmllint is part of libxml2, see URL +`http://www.xmlsoft.org/'." + :command ("xmllint" "--noout" + (option "--schema" flycheck-xml-xmllint-xsd-path) + "-") + :standard-input t + :error-patterns + ((error line-start "-:" line ": " (message) line-end)) + :modes (xml-mode nxml-mode)) + +(flycheck-define-checker yaml-jsyaml + "A YAML syntax checker using JS-YAML. + +See URL `https://github.com/nodeca/js-yaml'." + :command ("js-yaml") + :standard-input t + :error-patterns + ((error line-start + (or "JS-YAML" "YAMLException") ": " + (message) " at line " line ", column " column ":" + line-end)) + :modes yaml-mode + :next-checkers ((warning . cwl))) + +(flycheck-define-checker yaml-ruby + "A YAML syntax checker using Ruby's YAML parser. + +This syntax checker uses the YAML parser from Ruby's standard +library. + +See URL `http://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'." + :command ("ruby" "-ryaml" "-e" "begin; + YAML.load(STDIN); \ + rescue Exception => e; \ + STDERR.puts \"stdin:#{e}\"; \ + end") + :standard-input t + :error-patterns + ((error line-start "stdin:" (zero-or-more not-newline) ":" (message) + "at line " line " column " column line-end)) + :modes yaml-mode + :next-checkers ((warning . cwl))) + +(flycheck-def-config-file-var flycheck-yamllintrc yaml-yamllint ".yamllint") + +(flycheck-define-checker yaml-yamllint + "A YAML syntax checker using YAMLLint. +See URL `https://github.com/adrienverge/yamllint'." + :standard-input t + :command ("yamllint" "-f" "parsable" "-" + (config-file "-c" flycheck-yamllintrc)) + :error-patterns + ((error line-start + "stdin:" line ":" column ": [error] " (message) line-end) + (warning line-start + "stdin:" line ":" column ": [warning] " (message) line-end)) + :modes yaml-mode) + +(provide 'flycheck) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: + +;;; flycheck.el ends here diff --git a/flycheck.svg b/flycheck.svg new file mode 100644 index 0000000..6c7886a --- /dev/null +++ b/flycheck.svg @@ -0,0 +1,77 @@ + + + + + Flycheck Logo + + + + + image/svg+xml + + Flycheck Logo + + + Sebastian Wiesner + + + + + Copyright (C) 2014 Sebastian Wiesner + + + + + + + + + + + + + + + + + !Flyc + + diff --git a/maint/Makefile b/maint/Makefile new file mode 100644 index 0000000..ba06e5d --- /dev/null +++ b/maint/Makefile @@ -0,0 +1,59 @@ +# Copyright (c) 2012-2016 Sebastian Wiesner and Flycheck contributors + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +PYTHON = python3 +FLAKE8 = flake8 +PIP = pip3 +HAVE_PIP := $(shell sh -c "command -v $(PIP)") + +.DEFAULT_GOAL := help + +.PHONY: init +init: +ifndef HAVE_PIP + $(error "$(PIP) not available. Please run make help.") +endif +ifndef VIRTUAL_ENV + $(warning "No virtualenv active. Installing globally is not recommended.") +ifndef FORCE + $(error "Aborted. Run make FORCE=1 init to override or make help.") +endif +endif + pip install -r requirements.txt + +.PHONY: help +help: + @echo 'Available targets:' + @echo ' init: Install dependencies of maintenance scripts' + @echo ' check: Check maintenance scripts' + @echo ' release: Make a Flycheck release' + @echo '' + @echo 'You need Python 3.5 for all maintenance scripts' + @echo '' + @echo 'Run make init to install required libraries. It is recommended' + @echo 'that you use virtualenv (https://virtualenv.pypa.io/en/latest/)' + @echo 'to avoid a global installation of Python packages. make init' + @echo 'will warn you if you do not.' + +.PHONY: release +release: + @./release.py + +.PHONY: lint +lint: + $(FLAKE8) .. + +.PHONY: check +check: lint diff --git a/maint/flycheck-checkdoc.el b/maint/flycheck-checkdoc.el new file mode 100644 index 0000000..ec74570 --- /dev/null +++ b/maint/flycheck-checkdoc.el @@ -0,0 +1,88 @@ +;;; flycheck-checkdoc.el --- Flycheck: Checkdoc runner -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file provides checkdoc linting for Flycheck. It's intended for +;; non-interactive use, see "make checkdoc". + +;;; Code: + +(unless (version<= "25" emacs-version) + (user-error "Emacs 25 required for checkdoc")) + +(require 'subr-x) +(require 'seq) +(require 'f) +(require 'checkdoc) +(require 'flycheck-maint + (expand-file-name "flycheck-maint" + (file-name-directory (f-this-file)))) + +(defconst flycheck/source-dir (locate-dominating-file load-file-name "Cask") + "The source directory of Flycheck.") + +(defun flycheck/checkdoc-get-current-errors () + "Get the current checkdoc errors. + +Return a list of all error messages from checkdoc, and erase the +error message buffer, so that the next checkdoc check starts +fresh without previous errors. + +Each error is just a string with the complete human-readable +location and error message." + (with-current-buffer checkdoc-diagnostic-buffer + (unwind-protect + (progn + (goto-char (point-min)) + ;; Skip over the checkdoc header + (re-search-forward (rx line-start "***" (1+ not-newline) + ": checkdoc-current-buffer")) + (forward-line 1) + (let ((text (buffer-substring-no-properties (point) (point-max)))) + (and (not (string-empty-p text)) + (split-string text "\n")))) + (kill-buffer)))) + +(defun flycheck/checkdoc-file (filename) + "Run checkdoc on FILENAME and return a list of errors. + +Each error is just a string with the complete human-readable +location and error message." + (with-temp-buffer + ;; Visit the file to make sure that the filename is set, as some checkdoc + ;; lints only apply for buffers with filenames + (insert-file-contents filename 'visit) + (set-buffer-modified-p nil) + ;; Switch to Emacs Lisp mode to give checkdoc the proper syntax table, etc. + (delay-mode-hooks (emacs-lisp-mode)) + (setq delay-mode-hooks nil) + (let ((checkdoc-arguments-in-order-flag nil)) + (checkdoc-current-buffer 'take-notes)) + (flycheck/checkdoc-get-current-errors))) + +(defun flycheck/batch-checkdoc () + "Run checkdoc on all source files and exit." + (let ((errors (seq-mapcat #'flycheck/checkdoc-file + (flycheck/all-source-files)))) + (seq-do (lambda (err) (message "%s" err)) errors) + (kill-emacs (if errors 1 0)))) + +;;; flycheck-checkdoc.el ends here diff --git a/maint/flycheck-compile.el b/maint/flycheck-compile.el new file mode 100644 index 0000000..37b839a --- /dev/null +++ b/maint/flycheck-compile.el @@ -0,0 +1,76 @@ +;;; flycheck-compile.el --- Flycheck byte compiler -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file provides non-interactive byte compilation for Flycheck. +;; +;; It's essentially a wrapper around `batch-byte-compile' which sets some +;; additional byte compiler options for Flycheck. + +;;; Code: + +(require 'warnings) +(require 'bytecomp) + +(unless noninteractive + (error "This file must not be used interactively")) + +(defun flycheck/batch-byte-compile () + "Like `batch-byte-compile', but set additional flags. + +Specifically set `byte-compile-error-on-warn' to t on Emacs 25." + ;; Unfortunately `byte-compile-error-on-warn' does not quite what the name + ;; suggest because for whatever mysterious reason there's also + ;; `byte-compile-log-warning' used throughout Emacs' code which bypasses + ;; `byte-compile-error-on-warn' and instead logs an Emacs warning with + ;; `display-warning'. These warnings don't trigger errors even if + ;; `byte-compile-error-on-warn' is non-nil, which is… well, at least a very + ;; _unusual_ design decision, which leads the whole purpose of + ;; `byte-compile-error-on-warn' ad absurdum. + ;; + ;; To work around this mess (I'm sorry) we check the size of + ;; `byte-compile-log-buffer' after each file to check if any warnings end up + ;; there and exit with a non-zero code if the buffer is not empty. + ;; + ;; Unfortunately this means that we can't use `batch-byte-compile' (which is + ;; the proper API) and instead have to call the undocumented internal function + ;; `batch-byte-compile-file'. Yay, so now proper byte compilation of Flycheck + ;; depends on Emacs' internals, and much evil is accomplished. Can't get any + ;; worse, can it? + (let ((byte-compile-error-on-warn (version<= "25" emacs-version))) + (while command-line-args-left + (let ((filename (pop command-line-args-left))) + (unless (batch-byte-compile-file filename) + ;; Exit if compilation failed + (kill-emacs 1)) + (when (and byte-compile-error-on-warn + (get-buffer byte-compile-log-buffer) + (> (buffer-size (get-buffer byte-compile-log-buffer)) 0)) + ;; If there's anything in the log buffer (from the idiocy that is + ;; `byte-compile-log-warning') exit as well to _ALL_ warnings, really + ;; ALL WARNINGS. Got it, Emacs? Why are making my life so hard? At + ;; least we don't have to print the contents explicitly because + ;; `display-warnings' writes to standard whatever stream in batch + ;; mode. + (kill-emacs 1))))) + (kill-emacs 0)) + +;;; flycheck-compile.el ends here diff --git a/maint/flycheck-format.el b/maint/flycheck-format.el new file mode 100644 index 0000000..35681c9 --- /dev/null +++ b/maint/flycheck-format.el @@ -0,0 +1,151 @@ +;;; flycheck-format.el --- Flycheck: Source code formatter -*- lexical-binding: t; -*- + +;; Copyright (C) 2016, 2018 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file provides source code formatting for Flycheck. It's mainly intended +;; for non-interactive use, see "make format". + +;;; Code: + +(unless (version<= "25" emacs-version) + (user-error "Emacs 25 required for formatting")) + +(require 'seq) +(require 'rx) +(require 'f) +(require 'whitespace) +(require 'elisp-mode) + +;; Work around Emacs bug #39761 +(require 'cl-lib) + +(require 'flycheck-maint + (expand-file-name "flycheck-maint" + (file-name-directory (f-this-file)))) + +(defun flycheck/eval-and-format-buffer (filename) + "Format the current buffer for FILENAME. + +THIS FUNCTION HAS GLOBAL AND LOCAL SIDE EFFECTS. + +Evaluate the buffer to make all special indentation rules of +local definitions available before formatting. + +Switch the buffer to Emacs Lisp mode." + (let (delayed-mode-hooks) + (delay-mode-hooks (emacs-lisp-mode))) + ;; Load the file to make indentation rules from local definitions available. + ;; We load files instead of evaluating them because some files in our code + ;; rely on `load-file-name' and similar stuff. Don't load files which are + ;; already loaded, though, to prevent a recursive load of this file. + (unless (flycheck/already-loaded-p filename) + (let ((load-prefer-newer t)) ; Silence "newer" messages + (load filename 'noerror 'nomessage 'nosuffix))) + (widen) + (let ((indent-tabs-mode nil) + (whitespace-style + '(empty ; Cleanup empty lines at end + indentation::space ; Replace tabs with spaces + space-before-tab::space ; Replace tabs with spaces + trailing ; Remove trailing spaces + ))) + (let ((inhibit-message t)) + ;; Silence "Indenting region..." progress reporter + (indent-region (point-min) (point-max))) + (whitespace-cleanup-region (point-min) (point-max)))) + +(defun flycheck/check-long-lines (filename &optional length) + "Check FILENAME for lines longer than LENGTH. + +Display a message for any line longer than LENGTH. If LENGTH is +nil, default to `fill-column'. Return t if FILENAME has no long +lines, otherwise return nil. + +If FILENAME is a package file, return t regardless if there are +long lines or not." + (let ((long-lines 0) + (max-length (or length fill-column))) + (save-excursion + (goto-char (point-min)) + ;; If the file has a Commentary line, then it's a package and we start + ;; checking for long lines after the Commentary section. Lines before it + ;; may be too long but some are unsplittable. + (when (search-forward ";;; Commentary:" nil t) + (while (not (eobp)) + (end-of-line) + (when (> (current-column) max-length) + (message "%s:%d: line is over %d characters" + filename + (line-number-at-pos (point)) + max-length) + (setq long-lines (1+ long-lines))) + (forward-line 1)))) + (= long-lines 0))) + +(defun flycheck/can-have-long-lines (filename) + "Whether FILENAME can have arbitrarily long lines. + +Test files which contain error messages from checkers are allowed +to have long lines." + (string-match-p (rx (or "languages/test-" "flycheck-test.el")) filename)) + +(defun flycheck/file-formatted-p (filename) + "Check whether FILENAME is properly formatted. + +Return a non-nil value in this case, otherwise return nil." + (with-temp-buffer + (insert-file-contents filename) + (set-buffer-modified-p nil) + (flycheck/eval-and-format-buffer filename) + (and (not (buffer-modified-p)) + (or (flycheck/can-have-long-lines filename) + (flycheck/check-long-lines filename 80))))) + +(defun flycheck/batch-check-format () + "Check formatting of all sources." + (let ((bad-files (seq-remove #'flycheck/file-formatted-p + (flycheck/all-source-files)))) + (if (null bad-files) + (kill-emacs 0) + (seq-do (lambda (filename) (message "%s: misformatted!" filename)) + bad-files) + (kill-emacs 1)))) + +(defun flycheck/format-file (filename) + "Format FILENAME. + +Return a non-nil value if the file was formatted, and nil +otherwise." + (with-temp-file filename + (insert-file-contents filename) + (set-buffer-modified-p nil) + (flycheck/eval-and-format-buffer filename) + (buffer-modified-p))) + +(defun flycheck/batch-format () + "Format all Flycheck source files." + (let ((formatted-files (seq-filter #'flycheck/format-file + (flycheck/all-source-files)))) + (seq-do (lambda (filename) (message "Formatted %s" filename)) + formatted-files) + (kill-emacs 0))) + +;;; flycheck-format.el ends here diff --git a/maint/flycheck-maint.el b/maint/flycheck-maint.el new file mode 100644 index 0000000..f0f7979 --- /dev/null +++ b/maint/flycheck-maint.el @@ -0,0 +1,57 @@ +;;; flycheck-maint.el --- Flycheck: Maintenance library -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file provides helper functions for maintenance tools. + +;;; Code: + +(unless noninteractive + (error "This file must not be used interactively")) + +(defconst flycheck/source-dir (locate-dominating-file load-file-name "Cask") + "The source directory of Flycheck.") + +(defun flycheck/collect-el-files (directory &optional recursive) + "Collect all Emacs Lisp files in DIRECTORY. + +If RECURSIVE is given and non-nil collect files recursively." + (let ((fn-re (rx ".el" eos))) + (if recursive + (directory-files-recursively directory fn-re) + (directory-files directory 'full fn-re)))) + +(defun flycheck/all-source-files () + "Find all source files of Flycheck." + (append + (seq-mapcat (lambda (rel-name) + (flycheck/collect-el-files + (expand-file-name rel-name flycheck/source-dir))) + '("." "maint/" "doc/" "test/")) + (flycheck/collect-el-files + (expand-file-name "test/specs/" flycheck/source-dir) 'recursive))) + +(defun flycheck/already-loaded-p (filename) + "Whether FILENAME is already loaded." + (not (null (assoc filename load-history)))) + +(provide 'flycheck-maint) +;;; flycheck-maint.el ends here diff --git a/maint/release.py b/maint/release.py new file mode 100755 index 0000000..3e8a16c --- /dev/null +++ b/maint/release.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +# Copyright (C) 2017 Flycheck contributors +# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors + +# This file is not part of GNU Emacs. + +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. + +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. + +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +import re +import sys +import subprocess +from datetime import date +from collections import namedtuple +from pathlib import Path + +import requests +from git import Repo + + +SOURCE_DIR = Path(__file__).resolve().parent.parent +FLYCHECK_EL = SOURCE_DIR.joinpath('flycheck.el') +CHANGELOG = SOURCE_DIR.joinpath('CHANGES.rst') + +TRAVIS_ENDPOINT = 'https://api.travis-ci.org/repos/flycheck/flycheck' + +VERSION_HEADER_RE = re.compile( + r'^(?P