From 0e0a838cb20e752808584ec18c9ef2f3cdf0fff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raymundo=20V=C3=A1squez=20Ruiz?= Date: Sun, 27 Oct 2019 20:23:01 +0100 Subject: [PATCH] added more rust configurations --- .gitignore | 1 + elpa/archives/melpa/archive-contents | 24 +- elpa/dash-20191024.1908/dash-autoloads.el | 22 + elpa/dash-20191024.1908/dash-pkg.el | 2 + elpa/dash-20191024.1908/dash.el | 3044 +++++ elpa/dash-20191024.1908/dash.elc | Bin 0 -> 101188 bytes .../deferred-autoloads.el | 22 + elpa/deferred-20170901.1330/deferred-pkg.el | 2 + elpa/deferred-20170901.1330/deferred.el | 972 ++ elpa/deferred-20170901.1330/deferred.elc | Bin 0 -> 39152 bytes elpa/f-20190109.906/f-autoloads.el | 22 + elpa/f-20190109.906/f-pkg.el | 2 + elpa/f-20190109.906/f.el | 624 + elpa/f-20190109.906/f.elc | Bin 0 -> 20519 bytes .../flycheck-autoloads.el | 259 + .../flycheck-buttercup.el | 157 + elpa/flycheck-20191027.1608/flycheck-ert.el | 483 + elpa/flycheck-20191027.1608/flycheck-ert.elc | Bin 0 -> 23686 bytes elpa/flycheck-20191027.1608/flycheck-pkg.el | 16 + elpa/flycheck-20191027.1608/flycheck.el | 11256 ++++++++++++++++ elpa/flycheck-20191027.1608/flycheck.elc | Bin 0 -> 491072 bytes .../flycheck-rust-autoloads.el | 30 + .../flycheck-rust-pkg.el | 2 + .../flycheck-rust.el | 210 + .../flycheck-rust.elc | Bin 0 -> 5979 bytes .../pos-tip-autoloads.el | 22 + elpa/pos-tip-20150318.1513/pos-tip-pkg.el | 2 + elpa/pos-tip-20150318.1513/pos-tip.el | 980 ++ elpa/pos-tip-20150318.1513/pos-tip.elc | Bin 0 -> 25301 bytes elpa/s-20180406.808/s-autoloads.el | 22 + elpa/s-20180406.808/s-pkg.el | 2 + elpa/s-20180406.808/s.el | 747 + elpa/s-20180406.808/s.elc | Bin 0 -> 28329 bytes init.el | 7 +- 34 files changed, 18919 insertions(+), 13 deletions(-) create mode 100644 elpa/dash-20191024.1908/dash-autoloads.el create mode 100644 elpa/dash-20191024.1908/dash-pkg.el create mode 100644 elpa/dash-20191024.1908/dash.el create mode 100644 elpa/dash-20191024.1908/dash.elc create mode 100644 elpa/deferred-20170901.1330/deferred-autoloads.el create mode 100644 elpa/deferred-20170901.1330/deferred-pkg.el create mode 100644 elpa/deferred-20170901.1330/deferred.el create mode 100644 elpa/deferred-20170901.1330/deferred.elc create mode 100644 elpa/f-20190109.906/f-autoloads.el create mode 100644 elpa/f-20190109.906/f-pkg.el create mode 100644 elpa/f-20190109.906/f.el create mode 100644 elpa/f-20190109.906/f.elc create mode 100644 elpa/flycheck-20191027.1608/flycheck-autoloads.el create mode 100644 elpa/flycheck-20191027.1608/flycheck-buttercup.el create mode 100644 elpa/flycheck-20191027.1608/flycheck-ert.el create mode 100644 elpa/flycheck-20191027.1608/flycheck-ert.elc create mode 100644 elpa/flycheck-20191027.1608/flycheck-pkg.el create mode 100644 elpa/flycheck-20191027.1608/flycheck.el create mode 100644 elpa/flycheck-20191027.1608/flycheck.elc create mode 100644 elpa/flycheck-rust-20190319.1546/flycheck-rust-autoloads.el create mode 100644 elpa/flycheck-rust-20190319.1546/flycheck-rust-pkg.el create mode 100644 elpa/flycheck-rust-20190319.1546/flycheck-rust.el create mode 100644 elpa/flycheck-rust-20190319.1546/flycheck-rust.elc create mode 100644 elpa/pos-tip-20150318.1513/pos-tip-autoloads.el create mode 100644 elpa/pos-tip-20150318.1513/pos-tip-pkg.el create mode 100644 elpa/pos-tip-20150318.1513/pos-tip.el create mode 100644 elpa/pos-tip-20150318.1513/pos-tip.elc create mode 100644 elpa/s-20180406.808/s-autoloads.el create mode 100644 elpa/s-20180406.808/s-pkg.el create mode 100644 elpa/s-20180406.808/s.el create mode 100644 elpa/s-20180406.808/s.elc diff --git a/.gitignore b/.gitignore index 0ec05bb..a49b9b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ projectile-bookmarks.eld *.dat +*~ diff --git a/elpa/archives/melpa/archive-contents b/elpa/archives/melpa/archive-contents index 20de391..9808570 100644 --- a/elpa/archives/melpa/archive-contents +++ b/elpa/archives/melpa/archive-contents @@ -774,7 +774,7 @@ (scalariform . [(20190114 215) ((s (1 12 0)) (f (0 20 0))) "Format Scala code with scalariform." single ((:commit . "478a15ccb4f825aba73262bccd3e61ce7017f64b") (:keywords "processes" "scala" "scalariform") (:authors ("zwild" . "judezhao@outlook.com")) (:maintainer "zwild" . "judezhao@outlook.com") (:url . "https://github.com/zwild/scalariform"))]) (scala-mode . [(20190929 1522) nil "Major mode for editing Scala" tar ((:commit . "44772cbf1e1ade52bc5066555ff0aed68569aaec") (:keywords "languages") (:url . "https://github.com/hvesalai/emacs-scala-mode"))]) (scad-preview . [(20160206 1336) ((scad-mode (91 0))) "Preview SCAD models in real-time within Emacs" single ((:commit . "fee011589671cc8f1296cb6aa81553e5bb699819") (:authors ("zk_phi")) (:maintainer "zk_phi") (:url . "http://hins11.yu-yake.com/"))]) -(scad-mode . [(20190413 1246) nil "A major mode for editing OpenSCAD code" single ((:commit . "0fd84dbc4634f3be1b904fd31b1b49b05137c923") (:keywords "languages") (:authors ("Len Trigg, Łukasz Stelmach")) (:maintainer "Len Trigg" . "lenbok@gmail.com") (:url . "https://raw.github.com/openscad/openscad/master/contrib/scad-mode.el"))]) +(scad-mode . [(20190413 1246) nil "A major mode for editing OpenSCAD code" single ((:commit . "8c5970cd385b498affc5bdbdc6b364eb8196c707") (:keywords "languages") (:authors ("Len Trigg, Łukasz Stelmach")) (:maintainer "Len Trigg" . "lenbok@gmail.com") (:url . "https://raw.github.com/openscad/openscad/master/contrib/scad-mode.el"))]) (sbt-mode . [(20190929 1531) ((emacs (24 4))) "Interactive support for sbt projects" tar ((:commit . "5d2edadff23fe23e911379d6c2141d55b23e7254") (:keywords "languages") (:url . "https://github.com/hvesalai/emacs-sbt-mode"))]) (sayid . [(20190919 654) ((cider (0 21 0))) "sayid nREPL middleware client" single ((:commit . "277404a6bb0a979e195df5886fc143bb1d1f1e8c") (:authors ("Bill Piel" . "bill@billpiel.com")) (:maintainer "Bill Piel" . "bill@billpiel.com") (:url . "https://github.com/clojure-emacs/sayid"))]) (say-what-im-doing . [(20160706 1931) nil "dictate what you're doing with text to speech" single ((:commit . "5b2ce6783b02805bcac1107a149bfba3852cd9d5") (:keywords "text to speech" "dumb" "funny") (:authors ("Benaiah Mischenko")) (:maintainer "Benaiah Mischenko") (:url . "http://github.com/benaiah/say-what-im-doing"))]) @@ -1177,7 +1177,7 @@ (php-scratch . [(20161103 2217) ((emacs (24 3)) (s (1 11 0)) (php-mode (1 17 0))) "A scratch buffer to interactively evaluate php code" single ((:commit . "3aa66d1d53b84b779374edff7a7e6b5f2cd7575d") (:authors ("Tijs Mallaerts" . "tijs.mallaerts@gmail.com")) (:maintainer "Tijs Mallaerts" . "tijs.mallaerts@gmail.com"))]) (php-runtime . [(20181212 1825) ((emacs (25)) (cl-lib (0 5)) (f (0 20)) (s (1 7))) "Language binding bridge to PHP" single ((:commit . "017e0e70f07d6b25e37d5c5f4d271a914b677631") (:keywords "processes" "php") (:authors ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:url . "https://github.com/emacs-php/php-runtime.el"))]) (php-refactor-mode . [(20171124 635) nil "Minor mode to quickly and safely perform common refactorings" single ((:commit . "7a794b0618df2882b1bd586fdd698dba0bc5130d") (:keywords "php" "refactor") (:authors ("Matthew M. Keeler" . "keelerm84@gmail.com")) (:maintainer "Matthew M. Keeler" . "keelerm84@gmail.com") (:url . "https://github.com/keelerm84/php-refactor-mode.el"))]) -(php-mode . [(20190930 111) ((emacs (24 3))) "Major mode for editing PHP code" tar ((:commit . "5ba2a16e1751446502652021942f59f2e36aea41") (:keywords "languages" "php") (:authors ("Eric James Michael Ritz")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:url . "https://github.com/emacs-php/php-mode"))]) +(php-mode . [(20191027 1534) ((emacs (24 3))) "Major mode for editing PHP code" tar ((:commit . "429c612d904819e6f85938a95b5fc605c7f0a00c") (:keywords "languages" "php") (:authors ("Eric James Michael Ritz")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:url . "https://github.com/emacs-php/php-mode"))]) (php-eldoc . [(20140202 1941) nil "eldoc backend for php" tar ((:commit . "df05064146b884d9081e10657e32dc480f070cfe") (:authors ("sabof")) (:maintainer "sabof") (:url . "https://github.com/sabof/php-eldoc"))]) (php-cs-fixer . [(20190207 1126) ((cl-lib (0 5))) "php-cs-fixer wrapper." single ((:commit . "6540006710daf2b2d47576968ea826a83a40a6bf") (:keywords "languages" "php") (:authors ("Philippe Ivaldi for OVYA")) (:maintainer "Philippe Ivaldi for OVYA") (:url . "https://github.com/OVYA/php-cs-fixer"))]) (php-boris-minor-mode . [(20140209 1835) ((php-boris (0 0 1)) (highlight (0))) "a minor mode to evaluate PHP code in the Boris repl" single ((:commit . "c70e176dd6545f2d42ca3427e87b469635616d8a") (:keywords "php" "repl" "eval") (:authors ("steckerhalter")) (:maintainer "steckerhalter") (:url . "https://github.com/steckerhalter/php-boris-minor-mode"))]) @@ -1284,8 +1284,8 @@ (packed . [(20180318 1729) ((emacs (24 3))) "package manager agnostic Emacs Lisp package utilities" single ((:commit . "f350cc446c65b85bcc213265cd6dcadee1568762") (:keywords "compile" "convenience" "lisp" "package" "library") (:authors ("Jonas Bernoulli" . "jonas@bernoul.li")) (:maintainer "Jonas Bernoulli" . "jonas@bernoul.li") (:url . "https://github.com/emacscollective/packed"))]) (package-utils . [(20180514 1415) ((restart-emacs (0 1 1))) "Extensions for package.el" single ((:commit . "5621b95c56b55499f0463fd8b29501da25d861bd") (:keywords "package" "convenience") (:authors ("Philippe Vaucher" . "philippe.vaucher@gmail.com")) (:maintainer "Philippe Vaucher" . "philippe.vaucher@gmail.com") (:url . "https://github.com/Silex/package-utils"))]) (package-safe-delete . [(20150116 1607) ((emacs (24)) (epl (0 7 -4))) "Safely delete package.el packages" single ((:commit . "138171e4fc03c0ef05a8260cbb5cd2e114c1c194") (:authors ("Fanael Linithien" . "fanael4@gmail.com")) (:maintainer "Fanael Linithien" . "fanael4@gmail.com") (:url . "https://github.com/Fanael/package-safe-delete"))]) -(package-lint-flymake . [(20181117 856) ((emacs (26)) (package-lint (0 5))) "A package-lint Flymake backend" single ((:commit . "eb1867b5ad68b3ca762dad33cb1e30eed1cc7252") (:url . "https://github.com/purcell/package-lint"))]) -(package-lint . [(20191027 20) ((cl-lib (0 5)) (emacs (24 1)) (let-alist (1 0 6))) "A linting library for elisp package authors" tar ((:commit . "eb1867b5ad68b3ca762dad33cb1e30eed1cc7252") (:keywords "lisp") (:authors ("Steve Purcell" . "steve@sanityinc.com") ("Fanael Linithien" . "fanael4@gmail.com")) (:maintainer "Steve Purcell" . "steve@sanityinc.com") (:url . "https://github.com/purcell/package-lint"))]) +(package-lint-flymake . [(20181117 856) ((emacs (26)) (package-lint (0 5))) "A package-lint Flymake backend" single ((:commit . "bd22c75a15eab33dfdaa652d33c0a4adc489b3df") (:url . "https://github.com/purcell/package-lint"))]) +(package-lint . [(20191027 20) ((cl-lib (0 5)) (emacs (24 1)) (let-alist (1 0 6))) "A linting library for elisp package authors" tar ((:commit . "bd22c75a15eab33dfdaa652d33c0a4adc489b3df") (:keywords "lisp") (:authors ("Steve Purcell" . "steve@sanityinc.com") ("Fanael Linithien" . "fanael4@gmail.com")) (:maintainer "Steve Purcell" . "steve@sanityinc.com") (:url . "https://github.com/purcell/package-lint"))]) (package-filter . [(20161122 719) nil "package archive whitelist and blacklist" single ((:commit . "bc73b41aea1d65ca44ef1593ca13126df9bbb39e") (:authors ("Donald Ephraim Curtis" . "dcurtis@milkbox.net")) (:maintainer "Donald Ephraim Curtis" . "dcurtis@milkbox.net") (:url . "https://github.com/milkypostman/package-filter"))]) (package-build . [(20191010 616) ((cl-lib (0 5))) "Tools for assembling a package archive" tar ((:commit . "f761c2ffeed0daba9c17ac7571c7b979b6ceed64") (:keywords "tools") (:authors ("Donald Ephraim Curtis" . "dcurtis@milkbox.net")) (:maintainer "Donald Ephraim Curtis" . "dcurtis@milkbox.net"))]) (package+ . [(20190702 253) ((emacs (24 3))) "Extensions for the package library." single ((:commit . "2a99b8e27be1702d94ce077ecd75e1089fa18a32") (:keywords "extensions" "tools") (:authors ("Ryan Davis" . "ryand-ruby@zenspider.com")) (:maintainer "Ryan Davis" . "ryand-ruby@zenspider.com") (:url . "https://github.com/zenspider/package"))]) @@ -1926,7 +1926,7 @@ (lsp-pyre . [(20190406 335) ((lsp-mode (6 0))) "lsp-mode client for python using pyre" single ((:commit . "e177b8f5efd1a955b5753aeb5d1894e6d21be35a") (:authors ("John Allen" . "oss@porcnick.com")) (:maintainer "John Allen" . "oss@porcnick.com") (:url . "https://github.com/jra3/lsp-pyre"))]) (lsp-p4 . [(20190127 1049) ((lsp-mode (3 0))) "P4 support for lsp-mode" tar ((:commit . "54dd19d88cd561061ac3103dc452d6854e5899fa") (:keywords "lsp" "p4") (:authors ("Dmitri Makarov")) (:maintainer "Dmitri Makarov") (:url . "https://github.com/dmakarov/p4ls"))]) (lsp-origami . [(20190331 1723) ((origami (1 0)) (lsp-mode (20190326 522))) "origami.el support for lsp-mode" single ((:commit . "c7653602a2f2396b1a42d6053fd2be55fce8e0a2") (:keywords "languages" "lsp-mode") (:authors ("Vibhav Pant")) (:maintainer "Vibhav Pant") (:url . "https://github.com/emacs-lsp/lsp-origami"))]) -(lsp-mode . [(20191026 1912) ((emacs (25 1)) (dash (2 14 1)) (dash-functional (2 14 1)) (f (0 20 0)) (ht (2 0)) (spinner (1 7 3)) (markdown-mode (2 3))) "LSP mode" tar ((:commit . "366307e751ce71cc72216d4a9a0285270cf15515") (:keywords "languages") (:authors ("Vibhav Pant, Fangrui Song, Ivan Yonchovski")) (:maintainer "Vibhav Pant, Fangrui Song, Ivan Yonchovski") (:url . "https://github.com/emacs-lsp/lsp-mode"))]) +(lsp-mode . [(20191027 1345) ((emacs (25 1)) (dash (2 14 1)) (dash-functional (2 14 1)) (f (0 20 0)) (ht (2 0)) (spinner (1 7 3)) (markdown-mode (2 3))) "LSP mode" tar ((:commit . "1b4e25418c7d321808f33e132a4785c1ee075a7a") (:keywords "languages") (:authors ("Vibhav Pant, Fangrui Song, Ivan Yonchovski")) (:maintainer "Vibhav Pant, Fangrui Song, Ivan Yonchovski") (:url . "https://github.com/emacs-lsp/lsp-mode"))]) (lsp-julia . [(20191011 1005) ((emacs (25 1)) (lsp-mode (6 0)) (julia-mode (0 3))) "Julia support for lsp-mode" tar ((:commit . "6b0d1a3f32c5e6c5b4c0993f30303569a9e9e9bd") (:keywords "languages" "tools") (:authors ("Martin Wolke" . "vibhavp@gmail.com") ("Adam Beckmeyer" . "adam_git@thebeckmeyers.xyz") ("Guido Kraemer" . "gdkrmr@users.noreply.github.com")) (:maintainer "Adam Beckmeyer" . "adam_git@thebeckmeyers.xyz") (:url . "https://github.com/non-Jedi/lsp-julia"))]) (lsp-javacomp . [(20190124 1755) ((emacs (25 1)) (lsp-mode (3 0)) (s (1 2 0))) "Provide Java IDE features powered by JavaComp." single ((:commit . "82aa4ad6ca03a74565c35e855b318b1887bcd89b") (:keywords "java" "tools" "lsp") (:url . "https://github.com/tigersoldier/lsp-javacomp"))]) (lsp-java . [(20191016 1709) ((emacs (25 1)) (lsp-mode (6 0)) (markdown-mode (2 3)) (dash (2 14 1)) (f (0 20 0)) (ht (2 0)) (dash-functional (1 2 0)) (request (0 3 0)) (treemacs (2 5))) "Java support for lsp-mode" tar ((:commit . "52f61a539b9627122b39d9aff3885a1d94247d9a") (:keywords "java") (:url . "https://github.com/emacs-lsp/lsp-java"))]) @@ -2887,7 +2887,7 @@ (forth-mode . [(20170527 1930) nil "Programming language mode for Forth" tar ((:commit . "522256d98d1a909983bcfd3ae20c65226d5929b6") (:keywords "languages" "forth") (:authors ("Lars Brinkhoff" . "lars@nocrew.org")) (:maintainer "Lars Brinkhoff" . "lars@nocrew.org") (:url . "http://github.com/larsbrinkhoff/forth-mode"))]) (format-table . [(20181223 1616) ((emacs (25)) (dash (2 14 1))) "Parse and reformat tabular data." single ((:commit . "dfcae3a867e574577fc09a43b045889ff155b58f") (:keywords "data") (:authors ("Jason Duncan" . "jasond496@msn.com")) (:maintainer "Jason Duncan" . "jasond496@msn.com") (:url . "https://github.com/functionreturnfunction/format-table"))]) (format-sql . [(20150422 1333) nil "Use format-sql to make your SQL readable in directly Emacs." single ((:commit . "97f475c245cd6c81a72a265678e2087cee66ac7b") (:authors ("Friedrich Paetzke" . "paetzke@fastmail.fm")) (:maintainer "Friedrich Paetzke" . "paetzke@fastmail.fm") (:url . "https://github.com/paetzke/format-sql.el"))]) -(format-all . [(20191024 2151) ((emacs (24)) (cl-lib (0 5))) "Auto-format C, C++, JS, Python, Ruby and 40 other languages" single ((:commit . "a1d3ad48f21086788cd1effaf30227308a18d98f") (:keywords "languages" "util") (:authors ("Lassi Kortela" . "lassi@lassi.io")) (:maintainer "Lassi Kortela" . "lassi@lassi.io") (:url . "https://github.com/lassik/emacs-format-all-the-code"))]) +(format-all . [(20191027 1434) ((emacs (24)) (cl-lib (0 5))) "Auto-format C, C++, JS, Python, Ruby and 40 other languages" single ((:commit . "1ba755198b4622d132ceaec07c5b0a1f24caea33") (:keywords "languages" "util") (:authors ("Lassi Kortela" . "lassi@lassi.io")) (:maintainer "Lassi Kortela" . "lassi@lassi.io") (:url . "https://github.com/lassik/emacs-format-all-the-code"))]) (form-feed . [(20160102 2253) nil "Display ^L glyphs as horizontal lines" single ((:commit . "799ca3e72b20a59a755a094b8cead57f654f3170") (:keywords "faces") (:authors ("Vasilij Schneidermann" . "v.schneidermann@gmail.com")) (:maintainer "Vasilij Schneidermann" . "v.schneidermann@gmail.com") (:url . "https://github.com/wasamasa/form-feed"))]) (forge . [(20191017 1801) ((emacs (25 1)) (closql (1 0 0)) (dash (2 14 1)) (emacsql-sqlite (3 0 0)) (ghub (20190319)) (let-alist (1 0 5)) (magit (20190408)) (markdown-mode (2 3)) (transient (0 1 0))) "Access Git forges from Magit." tar ((:commit . "63cbf81f166fc71861d8e3d246df8e5ccedcb9bb"))]) (forest-blue-theme . [(20160627 842) ((emacs (24))) "Emacs theme with a dark background." single ((:commit . "58096ce1a25615d2bae806c3775bae3e2775019d") (:authors ("olkinn")) (:maintainer "olkinn"))]) @@ -3047,7 +3047,7 @@ (flycheck-ats2 . [(20170225 1636) ((emacs (24 1)) (flycheck (0 22))) "Flycheck: ATS2 support" single ((:commit . "9f77add8408462af35bdddf87e37a661880255e3") (:keywords "convenience" "tools" "languages") (:authors ("Mark Laws" . "mdl@60hz.org")) (:maintainer "Mark Laws" . "mdl@60hz.org") (:url . "http://github.com/drvink/flycheck-ats2"))]) (flycheck-apertium . [(20181211 1038) ((flycheck (0 25))) "Apertium checkers in flycheck" tar ((:commit . "22b60a17836477ac1edd15dc85b14f88ca871ba9") (:keywords "convenience" "tools" "xml") (:authors ("Kevin Brubeck Unhammer" . "unhammer+apertium@mm.st")) (:maintainer "Kevin Brubeck Unhammer" . "unhammer+apertium@mm.st") (:url . "http://wiki.apertium.org/wiki/Emacs"))]) (flycheck-ameba . [(20190720 1845) ((emacs (24 4)) (flycheck (30))) "Add support for Ameba to Flycheck" single ((:commit . "8383f07d760a31a0737be9b7bdaff2f1cff67bfd") (:keywords "tools" "crystal" "ameba") (:url . "https://github.com/crystal-ameba/ameba.el"))]) -(flycheck . [(20191022 1117) ((dash (2 12 1)) (pkg-info (0 4)) (let-alist (1 0 4)) (seq (1 11)) (emacs (24 3))) "On-the-fly syntax checking" tar ((:commit . "0eaf67211b83c062e598694d2ba4efb444dc1dc6") (:keywords "convenience" "languages" "tools") (:authors ("Sebastian Wiesner" . "swiesner@lunaryorn.com")) (:maintainer "Clément Pit-Claudel" . "clement.pitclaudel@live.com") (:url . "http://www.flycheck.org"))]) +(flycheck . [(20191027 1608) ((dash (2 12 1)) (pkg-info (0 4)) (let-alist (1 0 4)) (seq (1 11)) (emacs (24 3))) "On-the-fly syntax checking" tar ((:commit . "d8c5485143b6bdf339382138832bdd340b94c677") (:keywords "convenience" "languages" "tools") (:authors ("Sebastian Wiesner" . "swiesner@lunaryorn.com")) (:maintainer "Clément Pit-Claudel" . "clement.pitclaudel@live.com") (:url . "http://www.flycheck.org"))]) (flx-isearch . [(20180103 514) ((emacs (24)) (flx (20140821)) (cl-lib (0 5))) "Fuzzy incremental searching for emacs" single ((:commit . "f132fd6367e369885ab3a865fbfe20eee989bc0b") (:keywords "convenience" "search" "flx") (:authors ("PythonNut" . "pythonnut@pythonnut.com")) (:maintainer "PythonNut" . "pythonnut@pythonnut.com") (:url . "https://github.com/pythonnut/flx-isearch"))]) (flx-ido . [(20180117 1519) ((flx (0 1)) (cl-lib (0 3))) "flx integration for ido" single ((:commit . "46040d0b096a0340d91235561f27a959a61d0fef") (:authors ("Le Wang")) (:maintainer "Le Wang") (:url . "https://github.com/lewang/flx"))]) (flx . [(20151030 1812) ((cl-lib (0 3))) "fuzzy matching with good sorting" single ((:commit . "46040d0b096a0340d91235561f27a959a61d0fef") (:authors ("Le Wang")) (:maintainer "Le Wang") (:url . "https://github.com/lewang/flx"))]) @@ -3444,7 +3444,7 @@ (eimp . [(20120826 2039) nil "Emacs Image Manipulation Package" single ((:commit . "2e7536fe6d8f7faf1bad7a8ae37faba0162c3b4f") (:keywords "files" "frames") (:authors ("Matthew P. Hodges" . "MPHodges@member.fsf.org")) (:maintainer "Nic Ferrier" . "nferrier@ferrier.me.uk"))]) (eide . [(20191001 2003) nil "IDE interface" tar ((:commit . "eafa97e61383ef943bd6c3f8c7d50953257d4ae1"))]) (ego . [(20180301 104) ((emacs (24 5)) (ht (1 5)) (mustache (0 22)) (htmlize (1 47)) (org (8 0)) (dash (2 0 0)) (simple-httpd (1 4 5))) "a static site generator based on org mode, forked from org-page." tar ((:commit . "719809679c1a60887735db41abae53b61f08ef59"))]) -(eglot . [(20191026 2151) ((emacs (26 1)) (jsonrpc (1 0 7)) (flymake (1 0 5))) "Client for Language Server Protocol (LSP) servers" single ((:commit . "b4068181a8db1129dcd4eaf3e881f10067662e0e") (:keywords "convenience" "languages") (:authors ("João Távora" . "joaotavora@gmail.com")) (:maintainer "João Távora" . "joaotavora@gmail.com") (:url . "https://github.com/joaotavora/eglot"))]) +(eglot . [(20191027 1541) ((emacs (26 1)) (jsonrpc (1 0 7)) (flymake (1 0 5))) "Client for Language Server Protocol (LSP) servers" single ((:commit . "2ab8b59db44fd4dd9791ac203ac9f0915cc6824f") (:keywords "convenience" "languages") (:authors ("João Távora" . "joaotavora@gmail.com")) (:maintainer "João Távora" . "joaotavora@gmail.com") (:url . "https://github.com/joaotavora/eglot"))]) (egison-mode . [(20190714 236) nil "Egison editing mode" single ((:commit . "ad82bff8e9477310ad9b7806711cecdfe6d24f14") (:authors ("Satoshi Egi" . "egisatoshi@gmail.com")) (:maintainer "Satoshi Egi" . "egisatoshi@gmail.com") (:url . "https://github.com/egisatoshi/egison3/blob/master/elisp/egison-mode.el"))]) (egg . [(20181126 500) nil "Emacs Got Git - Emacs interface to Git" tar ((:commit . "00e768a78ac3d25f457eed667d02cac568480bf9") (:keywords "git" "version control" "release management") (:authors ("Bogolisk" . "bogolisk@gmail.com")) (:maintainer "Bogolisk" . "bogolisk@gmail.com"))]) (egalgo . [(20190706 1611) ((dash (2 14)) (emacs (24))) "Genetic algorithm for Emacs" single ((:commit . "d98524799f95c6c6bd972e52790e7e6b9003725c") (:keywords "data") (:authors ("ROCKTAKEY" . "rocktakey@gmail.com")) (:maintainer "ROCKTAKEY" . "rocktakey@gmail.com") (:url . "https://github.com/ROCKTAKEY/egalgo"))]) @@ -3537,7 +3537,7 @@ (dotenv-mode . [(20180207 1914) ((emacs (24 3))) "Major mode for .env files" single ((:commit . "f4c52bcd5313379b9f2460db7f7a33119dfa96ea") (:authors ("Preetpal S. Sohal")) (:maintainer "Preetpal S. Sohal") (:url . "https://github.com/preetpalS/emacs-dotenv-mode"))]) (dot-mode . [(20180312 2300) ((emacs (24 3))) "minor mode to repeat typing or commands" single ((:commit . "6ca22b73bcdae2363ee9641b822a60685df16a3e") (:keywords "convenience") (:authors ("Robert Wyrick" . "rob@wyrick.org")) (:maintainer "Robert Wyrick" . "rob@wyrick.org") (:url . "https://github.com/wyrickre/dot-mode"))]) (doom-themes . [(20191026 102) ((emacs (25 1)) (cl-lib (0 5))) "an opinionated pack of modern color-themes" tar ((:commit . "50da9726732e1f26fa0e4dd63f3f8041016db47d") (:keywords "dark" "light" "blue" "atom" "one" "theme" "neotree" "icons" "faces" "nova") (:authors ("Henrik Lissner ")) (:maintainer "Henrik Lissner" . "henrik@lissner.net") (:url . "https://github.com/hlissner/emacs-doom-theme"))]) -(doom-modeline . [(20191026 1931) ((emacs (25 1)) (all-the-icons (1 0 0)) (shrink-path (0 2 0)) (dash (2 11 0))) "A minimal and modern mode-line" tar ((:commit . "b2c0012252ec9b79e9ee790e766ae71a95ef41ff") (:keywords "faces" "mode-line") (:authors ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Vincent Zhang" . "seagle0128@gmail.com") (:url . "https://github.com/seagle0128/doom-modeline"))]) +(doom-modeline . [(20191027 821) ((emacs (25 1)) (all-the-icons (1 0 0)) (shrink-path (0 2 0)) (dash (2 11 0))) "A minimal and modern mode-line" tar ((:commit . "79c705019af38351324f60ba1e06224b1100ccd8") (:keywords "faces" "mode-line") (:authors ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Vincent Zhang" . "seagle0128@gmail.com") (:url . "https://github.com/seagle0128/doom-modeline"))]) (doom . [(20180301 2308) ((cl-lib (0 5))) "DOM implementation and manipulation library" single ((:commit . "e59040aefc92dd9b3134eb623624307fb9e4327b") (:keywords "xml" "dom") (:authors ("Alex Schroeder" . "alex@gnu.org") ("Henrik.Motakef" . "elisp@henrik-motakef.de") ("Katherine Whitlock" . "toroidal-code@gmail.com") ("Syohei YOSHIDA" . "syohex@gmail.com")) (:maintainer "Alex Schroeder") (:url . "http://www.github.com/kensanata/doom.el/"))]) (doneburn-theme . [(20181110 1857) nil "A light theme based on Bozhidar Batsov's Zenburn" single ((:commit . "6421d9e28d57cb73212c61ab7304abfe6f950ec9") (:keywords "faces" "themes") (:authors ("Manuel Uberti" . "manuel.uberti@inventati.org")) (:maintainer "Manuel Uberti" . "manuel.uberti@inventati.org") (:url . "http://github.com/manuel-uberti/doneburn-emacs"))]) (dollaro . [(20151123 1302) ((s (1 6 0))) "simple text templates" single ((:commit . "500127f0172ac7a1eec627e026b59136580a74ac") (:keywords "tools" "convenience") (:authors ("Alessandro Piras" . "laynor@gmail.com")) (:maintainer "Alessandro Piras" . "laynor@gmail.com"))]) @@ -3768,7 +3768,7 @@ (counsel-notmuch . [(20181203 935) ((emacs (24)) (ivy (0 10 0)) (notmuch (0 21)) (s (1 12 0))) "Search emails in Notmuch asynchronously with Ivy" single ((:commit . "a4a1562935e4180c42524c51609d1283e9be0688") (:keywords "mail") (:authors ("Alexander Fu Xi" . "fuxialexander@gmail.com")) (:maintainer "Alexander Fu Xi" . "fuxialexander@gmail.com") (:url . "https://github.com/fuxialexander/counsel-notmuch"))]) (counsel-gtags . [(20190923 1842) ((emacs (25 1)) (counsel (0 8 0)) (seq (1 0))) "ivy for GNU global" single ((:commit . "baac1a718aaa3ad6c439ab48903b12013de2cec0") (:authors ("Syohei YOSHIDA" . "syohex@gmail.com") ("Felipe Lema" . "felipelema@mortemale.org")) (:maintainer "Syohei YOSHIDA" . "syohex@gmail.com") (:url . "https://github.com/FelipeLema/emacs-counsel-gtags"))]) (counsel-ffdata . [(20191017 1237) ((emacs (25 1)) (counsel (0 11 0)) (emacsql (3 0 0))) "Use ivy to access firefox data" single ((:commit . "88c2348c4039d9e562bd3d9a364708b01037c283") (:keywords "convenience" "tools" "matching") (:authors ("Zhu Zihao" . "all_but_last@163.com")) (:maintainer "Zhu Zihao" . "all_but_last@163.com") (:url . "https://github.com/cireu/counsel-ffdata"))]) -(counsel-etags . [(20191014 50) ((emacs (24 4)) (counsel (0 10 0)) (ivy (0 10 0))) "Fast and complete Ctags/Etags solution using ivy" tar ((:commit . "b08ed51b763e29fc5deb2952eb7e5ba7c3677b4a") (:keywords "tools" "convenience") (:authors ("Chen Bin" . "chenbin.sh@gmail.com")) (:maintainer "Chen Bin" . "chenbin.sh@gmail.com") (:url . "http://github.com/redguardtoo/counsel-etags"))]) +(counsel-etags . [(20191027 1230) ((emacs (24 4)) (counsel (0 10 0)) (ivy (0 10 0))) "Fast and complete Ctags/Etags solution using ivy" tar ((:commit . "7b9cb71947943084cac22751cfe62c8507a3b378") (:keywords "tools" "convenience") (:authors ("Chen Bin" . "chenbin.sh@gmail.com")) (:maintainer "Chen Bin" . "chenbin.sh@gmail.com") (:url . "http://github.com/redguardtoo/counsel-etags"))]) (counsel-dash . [(20191021 1648) ((emacs (24 4)) (dash-docs (1 4 0)) (counsel (0 8 0)) (cl-lib (0 5))) "Browse dash docsets using Ivy" single ((:commit . "7027868d483b51d949b9f20fb8f34b122ca61520") (:keywords "dash" "ivy" "counsel") (:authors ("Nathan Kot" . "nk@nathankot.com")) (:maintainer "Nathan Kot" . "nk@nathankot.com") (:url . "https://github.com/nathankot/counsel-dash"))]) (counsel-css . [(20180302 1036) ((emacs (24 4)) (counsel (0 7 0)) (cl-lib (0 5))) "stylesheet-selector-aware swiper" single ((:commit . "0536af00236cdce1ed08b40dd46c917e8b4b8869") (:keywords "convenience" "tools" "counsel" "swiper" "selector" "css" "less" "scss") (:authors ("Henrik Lissner ")) (:maintainer "Henrik Lissner" . "henrik@lissner.net") (:url . "https://github.com/hlissner/emacs-counsel-css"))]) (counsel-codesearch . [(20180925 803) ((codesearch (1)) (counsel (0 10 0)) (emacs (24)) (ivy (0 10 0))) "Counsel interface for codesearch.el" single ((:commit . "b7989fad3e06f301c31d5e896c42b6cc549a0e0c") (:keywords "tools") (:authors ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainer "Austin Bingham" . "austin.bingham@gmail.com") (:url . "https://github.com/abingham/emacs-counsel-codesearch"))]) @@ -3969,7 +3969,7 @@ (chee . [(20171123 2233) ((dash (2 12 1)) (s (1 10 0)) (f (0 18 2))) "Interface to chee using dired and image-dired" tar ((:commit . "669ff9ee429f24c3c2d03b83d9cb9aec5f86bb8b") (:url . "https://github.com/eikek/chee/tree/release/0.3.0/emacs"))]) (checkbox . [(20141117 58) ((emacs (24)) (cl-lib (0 5))) "Quick manipulation of textual checkboxes" single ((:commit . "335afa4404adf72973195a580458927004664d98") (:keywords "convenience") (:authors ("Cameron Desautels" . "camdez@gmail.com")) (:maintainer "Cameron Desautels" . "camdez@gmail.com") (:url . "http://github.com/camdez/checkbox.el"))]) (cheatsheet . [(20170126 2150) ((emacs (24)) (cl-lib (0 5))) "create your own cheatsheet" single ((:commit . "e4f8e0110167ea16a17a74517d1f10cb7ff805b8") (:keywords "convenience" "usability") (:authors ("Shirin Nikita" . "shirin.nikita@gmail.com")) (:maintainer "Shirin Nikita" . "shirin.nikita@gmail.com") (:url . "http://github.com/darksmile/cheatsheet/"))]) -(cheat-sh . [(20190520 1339) ((emacs (24))) "Interact with cheat.sh" single ((:commit . "4b29b3e7be0eadeddc8424b327cb2a2726f751f4") (:keywords "docs" "help") (:authors ("Dave Pearson" . "davep@davep.org")) (:maintainer "Dave Pearson" . "davep@davep.org") (:url . "https://github.com/davep/cheat-sh.el"))]) +(cheat-sh . [(20191027 1038) ((emacs (25 1))) "Interact with cheat.sh" single ((:commit . "bd970d7c576b8720d63a1e7fd88ea8a943f2160b") (:keywords "docs" "help") (:authors ("Dave Pearson" . "davep@davep.org")) (:maintainer "Dave Pearson" . "davep@davep.org") (:url . "https://github.com/davep/cheat-sh.el"))]) (chatwork . [(20170511 442) nil "ChatWork client for Emacs" single ((:commit . "fea231d479f06bf40dbfcf45de143eecc9ed744c") (:keywords "web") (:authors ("Masayuki Ataka" . "masayuki.ataka@gmail.com")) (:maintainer "Masayuki Ataka" . "masayuki.ataka@gmail.com") (:url . "https://github.com/ataka/chatwork"))]) (charmap . [(20160309 946) nil "Unicode table for Emacs" single ((:commit . "bd4b3e466d7a9433cf35167e3a68ec74fe631bb2") (:keywords "unicode" "character" "ucs") (:authors ("Anan Mikami" . "lateau@gmail.com")) (:maintainer "Anan Mikami" . "lateau@gmail.com") (:url . "https://github.com/lateau/charmap"))]) (char-menu . [(20190713 1343) ((emacs (24 3)) (avy-menu (0 1))) "Create your own menu for fast insertion of arbitrary symbols" single ((:commit . "e73949b26406a397a70624f6086183cb41ce1353") (:keywords "convenience" "editing") (:authors ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainer "Mark Karpov" . "markkarpov92@gmail.com") (:url . "https://github.com/mrkkrp/char-menu"))]) @@ -3982,7 +3982,7 @@ (cframe . [(20190616 1946) ((emacs (25)) (buffer-manage (0 9)) (dash (2 13 0))) "customize a frame and fast switch size and positions" single ((:commit . "38026cbd004231c5525bea31723ced39311bb408") (:keywords "frame" "customize") (:authors ("Paul Landes")) (:maintainer "Paul Landes") (:url . "https://github.com/plandes/cframe"))]) (cfml-mode . [(20190617 1130) ((emacs (25))) "Emacs mode for editing CFML files" single ((:commit . "b06d7cee2af0ed5d55a94f0db80fc1f429a1829a") (:authors ("Andrew Myers" . "am2605@gmail.com")) (:maintainer "Andrew Myers" . "am2605@gmail.com") (:url . "https://github.com/am2605/cfml-mode"))]) (cff . [(20160118 2018) ((cl-lib (0 5)) (emacs (24))) "Search of the C/C++ file header by the source and vice versa" single ((:commit . "b6ab2a28e64ef06f281ec74cfe3114e450644dfa") (:keywords "find-file") (:authors ("Alexey Veretennikov" . "alexey.veretennikov@gmail.com")) (:maintainer "Alexey Veretennikov" . "alexey.veretennikov@gmail.com") (:url . "https://github.com/fourier/cff"))]) -(cfengine-code-style . [(20171115 2108) nil "C code style for CFEngine project." single ((:commit . "510a0d3506cca601195d53d0ce885a25b4084e1b") (:authors ("Mikhail Gusarov" . "mikhail.gusarov@cfengine.com")) (:maintainer "Mikhail Gusarov" . "mikhail.gusarov@cfengine.com") (:url . "https://github.com/cfengine/core"))]) +(cfengine-code-style . [(20171115 2108) nil "C code style for CFEngine project." single ((:commit . "c6065c0c999ed523c7438e87b99cbaecbd633c5a") (:authors ("Mikhail Gusarov" . "mikhail.gusarov@cfengine.com")) (:maintainer "Mikhail Gusarov" . "mikhail.gusarov@cfengine.com") (:url . "https://github.com/cfengine/core"))]) (ceylon-mode . [(20180606 1324) ((emacs (25))) "Major mode for editing Ceylon source code" single ((:commit . "948515672bc596dc118e8e3ede3ede5ec6a3c95a") (:keywords "languages" "ceylon") (:authors ("Lucas Werkmeister" . "mail@lucaswerkmeister.de")) (:maintainer "Lucas Werkmeister" . "mail@lucaswerkmeister.de") (:url . "https://github.com/lucaswerkmeister/ceylon-mode"))]) (cerbere . [(20181113 1641) ((pkg-info (0 5))) "Unit testing in Emacs for several programming languages" tar ((:commit . "c667c165d9c1657f13d2d46f09ba21b61f9402cc") (:keywords "python" "go" "php" "phpunit" "elisp" "ert" "tests" "tdd") (:authors ("Nicolas Lamirault" . "nicolas.lamirault@gmail.com")) (:maintainer "Nicolas Lamirault" . "nicolas.lamirault@gmail.com") (:url . "https://github.com/nlamirault/cerbere"))]) (centimacro . [(20140306 1427) nil "Assign multiple macros as global key bindings" single ((:commit . "1b97a9b558ed9c49d5da1bfbf29b2506575c2742") (:keywords "macros") (:authors ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainer "Oleh Krehel" . "ohwoeowho@gmail.com") (:url . "https://github.com/abo-abo/centimacro"))]) diff --git a/elpa/dash-20191024.1908/dash-autoloads.el b/elpa/dash-20191024.1908/dash-autoloads.el new file mode 100644 index 0000000..8bacbc8 --- /dev/null +++ b/elpa/dash-20191024.1908/dash-autoloads.el @@ -0,0 +1,22 @@ +;;; dash-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "dash" "dash.el" (0 0 0 0)) +;;; Generated autoloads from dash.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dash" '("dash-" "-keep" "-butlast" "-non" "-only-some" "-zip" "-e" "->" "-a" "-gr" "-when-let" "-d" "-l" "-s" "-p" "-r" "-m" "-i" "-f" "-u" "-value-to-list" "-t" "--" "-c" "!cons" "!cdr"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; dash-autoloads.el ends here diff --git a/elpa/dash-20191024.1908/dash-pkg.el b/elpa/dash-20191024.1908/dash-pkg.el new file mode 100644 index 0000000..3bca55c --- /dev/null +++ b/elpa/dash-20191024.1908/dash-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "dash" "20191024.1908" "A modern list library for Emacs" 'nil :commit "9631947f2fbeed58b1d07a3ebc1340a3626b2823" :keywords '("lists") :authors '(("Magnar Sveen" . "magnars@gmail.com")) :maintainer '("Magnar Sveen" . "magnars@gmail.com")) diff --git a/elpa/dash-20191024.1908/dash.el b/elpa/dash-20191024.1908/dash.el new file mode 100644 index 0000000..f1b3e06 --- /dev/null +++ b/elpa/dash-20191024.1908/dash.el @@ -0,0 +1,3044 @@ +;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2016 Free Software Foundation, Inc. + +;; Author: Magnar Sveen +;; Version: 2.16.0 +;; Package-Version: 20191024.1908 +;; Keywords: lists + +;; 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: + +;; A modern list api for Emacs. +;; +;; See documentation on https://github.com/magnars/dash.el#functions +;; +;; **Please note** The lexical binding in this file is not utilised at the +;; moment. We will take full advantage of lexical binding in an upcoming 3.0 +;; release of Dash. In the meantime, we've added the pragma to avoid a bug that +;; you can read more about in https://github.com/magnars/dash.el/issues/130. +;; + +;;; Code: + +;; TODO: `gv' was introduced in Emacs 24.3, so remove this and all +;; calls to `defsetf' when support for earlier versions is dropped. +(eval-when-compile + (unless (fboundp 'gv-define-setter) + (require 'cl))) + +(defgroup dash () + "Customize group for dash.el" + :group 'lisp + :prefix "dash-") + +(defun dash--enable-fontlock (symbol value) + (when value + (dash-enable-font-lock)) + (set-default symbol value)) + +(defcustom dash-enable-fontlock nil + "If non-nil, enable fontification of dash functions, macros and +special values." + :type 'boolean + :set 'dash--enable-fontlock + :group 'dash) + +(defmacro !cons (car cdr) + "Destructive: Set CDR to the cons of CAR and CDR." + `(setq ,cdr (cons ,car ,cdr))) + +(defmacro !cdr (list) + "Destructive: Set LIST to the cdr of LIST." + `(setq ,list (cdr ,list))) + +(defmacro --each (list &rest body) + "Anaphoric form of `-each'." + (declare (debug (form body)) + (indent 1)) + (let ((l (make-symbol "list"))) + `(let ((,l ,list) + (it-index 0)) + (while ,l + (let ((it (car ,l))) + ,@body) + (setq it-index (1+ it-index)) + (!cdr ,l))))) + +(defmacro -doto (eval-initial-value &rest forms) + "Eval a form, then insert that form as the 2nd argument to other forms. +The EVAL-INITIAL-VALUE form is evaluated once. Its result is +passed to FORMS, which are then evaluated sequentially. Returns +the target form." + (declare (indent 1)) + (let ((retval (make-symbol "value"))) + `(let ((,retval ,eval-initial-value)) + ,@(mapcar (lambda (form) + (if (sequencep form) + `(,(-first-item form) ,retval ,@(cdr form)) + `(funcall form ,retval))) + forms) + ,retval))) + +(defmacro --doto (eval-initial-value &rest forms) + "Anaphoric form of `-doto'. +Note: `it' is not required in each form." + (declare (indent 1)) + `(let ((it ,eval-initial-value)) + ,@forms + it)) + +(defun -each (list fn) + "Call FN with every item in LIST. Return nil, used for side-effects only." + (--each list (funcall fn it))) + +(put '-each 'lisp-indent-function 1) + +(defalias '--each-indexed '--each) + +(defun -each-indexed (list fn) + "Call (FN index item) for each item in LIST. + +In the anaphoric form `--each-indexed', the index is exposed as symbol `it-index'. + +See also: `-map-indexed'." + (--each list (funcall fn it-index it))) +(put '-each-indexed 'lisp-indent-function 1) + +(defmacro --each-while (list pred &rest body) + "Anaphoric form of `-each-while'." + (declare (debug (form form body)) + (indent 2)) + (let ((l (make-symbol "list")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,c t) + (it-index 0)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) (setq ,c nil) ,@body)) + (setq it-index (1+ it-index)) + (!cdr ,l))))) + +(defun -each-while (list pred fn) + "Call FN with every item in LIST while (PRED item) is non-nil. +Return nil, used for side-effects only." + (--each-while list (funcall pred it) (funcall fn it))) + +(put '-each-while 'lisp-indent-function 2) + +(defmacro --each-r (list &rest body) + "Anaphoric form of `-each-r'." + (declare (debug (form body)) + (indent 1)) + (let ((v (make-symbol "vector"))) + ;; Implementation note: building vector is considerably faster + ;; than building a reversed list (vector takes less memory, so + ;; there is less GC), plus length comes naturally. In-place + ;; 'nreverse' would be faster still, but BODY would be able to see + ;; that, even if modification was reversed before we return. + `(let* ((,v (vconcat ,list)) + (it-index (length ,v)) + it) + (while (> it-index 0) + (setq it-index (1- it-index)) + (setq it (aref ,v it-index)) + ,@body)))) + +(defun -each-r (list fn) + "Call FN with every item in LIST in reversed order. + Return nil, used for side-effects only." + (--each-r list (funcall fn it))) + +(defmacro --each-r-while (list pred &rest body) + "Anaphoric form of `-each-r-while'." + (declare (debug (form form body)) + (indent 2)) + (let ((v (make-symbol "vector"))) + `(let* ((,v (vconcat ,list)) + (it-index (length ,v)) + it) + (while (> it-index 0) + (setq it-index (1- it-index)) + (setq it (aref ,v it-index)) + (if (not ,pred) + (setq it-index -1) + ,@body))))) + +(defun -each-r-while (list pred fn) + "Call FN with every item in reversed LIST while (PRED item) is non-nil. +Return nil, used for side-effects only." + (--each-r-while list (funcall pred it) (funcall fn it))) + +(defmacro --dotimes (num &rest body) + "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1." + (declare (debug (form body)) + (indent 1)) + (let ((n (make-symbol "num"))) + `(let ((,n ,num) + (it 0)) + (while (< it ,n) + ,@body + (setq it (1+ it)))))) + +(defun -dotimes (num fn) + "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1." + (--dotimes num (funcall fn it))) + +(put '-dotimes 'lisp-indent-function 1) + +(defun -map (fn list) + "Return a new list consisting of the result of applying FN to the items in LIST." + (mapcar fn list)) + +(defmacro --map (form list) + "Anaphoric form of `-map'." + (declare (debug (form form))) + `(mapcar (lambda (it) ,form) ,list)) + +(defmacro --reduce-from (form initial-value list) + "Anaphoric form of `-reduce-from'." + (declare (debug (form form form))) + `(let ((acc ,initial-value)) + (--each ,list (setq acc ,form)) + acc)) + +(defun -reduce-from (fn initial-value list) + "Return the result of applying FN to INITIAL-VALUE and the +first item in LIST, then applying FN to that result and the 2nd +item, etc. If LIST contains no items, return INITIAL-VALUE and +do not call FN. + +In the anaphoric form `--reduce-from', the accumulated value is +exposed as symbol `acc'. + +See also: `-reduce', `-reduce-r'" + (--reduce-from (funcall fn acc it) initial-value list)) + +(defmacro --reduce (form list) + "Anaphoric form of `-reduce'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reduce-from ,form (car ,lv) (cdr ,lv)) + (let (acc it) ,form))))) + +(defun -reduce (fn list) + "Return the result of applying FN to the first 2 items in LIST, +then applying FN to that result and the 3rd item, etc. If LIST +contains no items, return the result of calling FN with no +arguments. If LIST contains a single item, return that item +and do not call FN. + +In the anaphoric form `--reduce', the accumulated value is +exposed as symbol `acc'. + +See also: `-reduce-from', `-reduce-r'" + (if list + (-reduce-from fn (car list) (cdr list)) + (funcall fn))) + +(defmacro --reduce-r-from (form initial-value list) + "Anaphoric version of `-reduce-r-from'." + (declare (debug (form form form))) + `(--reduce-from ,form ,initial-value (reverse ,list))) + +(defun -reduce-r-from (fn initial-value list) + "Replace conses with FN, nil with INITIAL-VALUE and evaluate +the resulting expression. If LIST is empty, INITIAL-VALUE is +returned and FN is not called. + +Note: this function works the same as `-reduce-from' but the +operation associates from right instead of from left. + +See also: `-reduce-r', `-reduce'" + (--reduce-r-from (funcall fn it acc) initial-value list)) + +(defmacro --reduce-r (form list) + "Anaphoric version of `-reduce-r'." + (declare (debug (form form))) + `(--reduce ,form (reverse ,list))) + +(defun -reduce-r (fn list) + "Replace conses with FN and evaluate the resulting expression. +The final nil is ignored. If LIST contains no items, return the +result of calling FN with no arguments. If LIST contains a single +item, return that item and do not call FN. + +The first argument of FN is the new item, the second is the +accumulated value. + +Note: this function works the same as `-reduce' but the operation +associates from right instead of from left. + +See also: `-reduce-r-from', `-reduce'" + (if list + (--reduce-r (funcall fn it acc) list) + (funcall fn))) + +(defun -reductions-from (fn init list) + "Return a list of the intermediate values of the reduction. + +See `-reduce-from' for explanation of the arguments. + +See also: `-reductions', `-reductions-r', `-reduce-r'" + (nreverse (--reduce-from (cons (funcall fn (car acc) it) acc) (list init) list))) + +(defun -reductions (fn list) + "Return a list of the intermediate values of the reduction. + +See `-reduce' for explanation of the arguments. + +See also: `-reductions-from', `-reductions-r', `-reduce-r'" + (and list (-reductions-from fn (car list) (cdr list)))) + +(defun -reductions-r-from (fn init list) + "Return a list of the intermediate values of the reduction. + +See `-reduce-r-from' for explanation of the arguments. + +See also: `-reductions-r', `-reductions', `-reduce'" + (--reduce-r-from (cons (funcall fn it (car acc)) acc) (list init) list)) + +(defun -reductions-r (fn list) + "Return a list of the intermediate values of the reduction. + +See `-reduce-r' for explanation of the arguments. + +See also: `-reductions-r-from', `-reductions', `-reduce'" + (when list + (let ((rev (reverse list))) + (--reduce-from (cons (funcall fn it (car acc)) acc) + (list (car rev)) + (cdr rev))))) + +(defmacro --filter (form list) + "Anaphoric form of `-filter'. + +See also: `--remove'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (when ,form (!cons it ,r))) + (nreverse ,r)))) + +(defun -filter (pred list) + "Return a new list of the items in LIST for which PRED returns a non-nil value. + +Alias: `-select' + +See also: `-keep', `-remove'." + (--filter (funcall pred it) list)) + +(defalias '-select '-filter) +(defalias '--select '--filter) + +(defmacro --remove (form list) + "Anaphoric form of `-remove'. + +See also `--filter'." + (declare (debug (form form))) + `(--filter (not ,form) ,list)) + +(defun -remove (pred list) + "Return a new list of the items in LIST for which PRED returns nil. + +Alias: `-reject' + +See also: `-filter'." + (--remove (funcall pred it) list)) + +(defalias '-reject '-remove) +(defalias '--reject '--remove) + +(defun -remove-first (pred list) + "Return a new list with the first item matching PRED removed. + +Alias: `-reject-first' + +See also: `-remove', `-map-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cdr list)) + (nreverse front)))) + +(defmacro --remove-first (form list) + "Anaphoric form of `-remove-first'." + (declare (debug (form form))) + `(-remove-first (lambda (it) ,form) ,list)) + +(defalias '-reject-first '-remove-first) +(defalias '--reject-first '--remove-first) + +(defun -remove-last (pred list) + "Return a new list with the last item matching PRED removed. + +Alias: `-reject-last' + +See also: `-remove', `-map-last'" + (nreverse (-remove-first pred (reverse list)))) + +(defmacro --remove-last (form list) + "Anaphoric form of `-remove-last'." + (declare (debug (form form))) + `(-remove-last (lambda (it) ,form) ,list)) + +(defalias '-reject-last '-remove-last) +(defalias '--reject-last '--remove-last) + +(defun -remove-item (item list) + "Remove all occurences of ITEM from LIST. + +Comparison is done with `equal'." + (declare (pure t) (side-effect-free t)) + (--remove (equal it item) list)) + +(defmacro --keep (form list) + "Anaphoric form of `-keep'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (m (make-symbol "mapped"))) + `(let (,r) + (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r)))) + (nreverse ,r)))) + +(defun -keep (fn list) + "Return a new list of the non-nil results of applying FN to the items in LIST. + +If you want to select the original items satisfying a predicate use `-filter'." + (--keep (funcall fn it) list)) + +(defun -non-nil (list) + "Return all non-nil elements of LIST." + (declare (pure t) (side-effect-free t)) + (-remove 'null list)) + +(defmacro --map-indexed (form list) + "Anaphoric form of `-map-indexed'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list + (!cons ,form ,r)) + (nreverse ,r)))) + +(defun -map-indexed (fn list) + "Return a new list consisting of the result of (FN index item) for each item in LIST. + +In the anaphoric form `--map-indexed', the index is exposed as symbol `it-index'. + +See also: `-each-indexed'." + (--map-indexed (funcall fn it-index it) list)) + +(defmacro --map-when (pred rep list) + "Anaphoric form of `-map-when'." + (declare (debug (form form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (!cons (if ,pred ,rep it) ,r)) + (nreverse ,r)))) + +(defun -map-when (pred rep list) + "Return a new list where the elements in LIST that do not match the PRED function +are unchanged, and where the elements in LIST that do match the PRED function are mapped +through the REP function. + +Alias: `-replace-where' + +See also: `-update-at'" + (--map-when (funcall pred it) (funcall rep it) list)) + +(defalias '-replace-where '-map-when) +(defalias '--replace-where '--map-when) + +(defun -map-first (pred rep list) + "Replace first item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list))) + (nreverse front)))) + +(defmacro --map-first (pred rep list) + "Anaphoric form of `-map-first'." + `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -map-last (pred rep list) + "Replace last item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-last'" + (nreverse (-map-first pred rep (reverse list)))) + +(defmacro --map-last (pred rep list) + "Anaphoric form of `-map-last'." + `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -replace (old new list) + "Replace all OLD items in LIST with NEW. + +Elements are compared using `equal'. + +See also: `-replace-at'" + (declare (pure t) (side-effect-free t)) + (--map-when (equal it old) new list)) + +(defun -replace-first (old new list) + "Replace the first occurence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-first'" + (declare (pure t) (side-effect-free t)) + (--map-first (equal old it) new list)) + +(defun -replace-last (old new list) + "Replace the last occurence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-last'" + (declare (pure t) (side-effect-free t)) + (--map-last (equal old it) new list)) + +(defmacro --mapcat (form list) + "Anaphoric form of `-mapcat'." + (declare (debug (form form))) + `(apply 'append (--map ,form ,list))) + +(defun -mapcat (fn list) + "Return the concatenation of the result of mapping FN over LIST. +Thus function FN should return a list." + (--mapcat (funcall fn it) list)) + +(defun -flatten (l) + "Take a nested list L and return its contents as a single, flat list. + +Note that because `nil' represents a list of zero elements (an +empty list), any mention of nil in L will disappear after +flattening. If you need to preserve nils, consider `-flatten-n' +or map them to some unique symbol and then map them back. + +Conses of two atoms are considered \"terminals\", that is, they +aren't flattened further. + +See also: `-flatten-n'" + (declare (pure t) (side-effect-free t)) + (if (and (listp l) (listp (cdr l))) + (-mapcat '-flatten l) + (list l))) + +(defmacro --iterate (form init n) + "Anaphoric version of `-iterate'." + (declare (debug (form form form))) + `(-iterate (lambda (it) ,form) ,init ,n)) + +(defun -flatten-n (num list) + "Flatten NUM levels of a nested LIST. + +See also: `-flatten'" + (declare (pure t) (side-effect-free t)) + (-last-item (--iterate (--mapcat (-list it) it) list (1+ num)))) + +(defun -concat (&rest lists) + "Return a new list with the concatenation of the elements in the supplied LISTS." + (declare (pure t) (side-effect-free t)) + (apply 'append lists)) + +(defalias '-copy 'copy-sequence + "Create a shallow copy of LIST. + +\(fn LIST)") + +(defun -splice (pred fun list) + "Splice lists generated by FUN in place of elements matching PRED in LIST. + +FUN takes the element matching PRED as input. + +This function can be used as replacement for `,@' in case you +need to splice several lists at marked positions (for example +with keywords). + +See also: `-splice-list', `-insert-at'" + (let (r) + (--each list + (if (funcall pred it) + (let ((new (funcall fun it))) + (--each new (!cons it r))) + (!cons it r))) + (nreverse r))) + +(defmacro --splice (pred form list) + "Anaphoric form of `-splice'." + `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list)) + +(defun -splice-list (pred new-list list) + "Splice NEW-LIST in place of elements matching PRED in LIST. + +See also: `-splice', `-insert-at'" + (-splice pred (lambda (_) new-list) list)) + +(defmacro --splice-list (pred new-list list) + "Anaphoric form of `-splice-list'." + `(-splice-list (lambda (it) ,pred) ,new-list ,list)) + +(defun -cons* (&rest args) + "Make a new list from the elements of ARGS. + +The last 2 members of ARGS are used as the final cons of the +result so if the final member of ARGS is not a list the result is +a dotted list." + (declare (pure t) (side-effect-free t)) + (-reduce-r 'cons args)) + +(defun -snoc (list elem &rest elements) + "Append ELEM to the end of the list. + +This is like `cons', but operates on the end of list. + +If ELEMENTS is non nil, append these to the list as well." + (-concat list (list elem) elements)) + +(defmacro --first (form list) + "Anaphoric form of `-first'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not ,n) + (when ,form (setq ,n it))) + ,n))) + +(defun -first (pred list) + "Return the first x in LIST where (PRED x) is non-nil, else nil. + +To get the first item in the list no questions asked, use `car'. + +Alias: `-find'" + (--first (funcall pred it) list)) + +(defalias '-find '-first) +(defalias '--find '--first) + +(defmacro --some (form list) + "Anaphoric form of `-some'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not ,n) + (setq ,n ,form)) + ,n))) + +(defun -some (pred list) + "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil. + +Alias: `-any'" + (--some (funcall pred it) list)) + +(defalias '-any '-some) +(defalias '--any '--some) + +(defmacro --last (form list) + "Anaphoric form of `-last'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each ,list + (when ,form (setq ,n it))) + ,n))) + +(defun -last (pred list) + "Return the last x in LIST where (PRED x) is non-nil, else nil." + (--last (funcall pred it) list)) + +(defalias '-first-item 'car + "Return the first item of LIST, or nil on an empty list. + +See also: `-second-item', `-last-item'. + +\(fn LIST)") + +;; Ensure that calls to `-first-item' are compiled to a single opcode, +;; just like `car'. +(put '-first-item 'byte-opcode 'byte-car) +(put '-first-item 'byte-compile 'byte-compile-one-arg) + +(defalias '-second-item 'cadr + "Return the second item of LIST, or nil if LIST is too short. + +See also: `-third-item'. + +\(fn LIST)") + +(defalias '-third-item + (if (fboundp 'caddr) + #'caddr + (lambda (list) (car (cddr list)))) + "Return the third item of LIST, or nil if LIST is too short. + +See also: `-fourth-item'. + +\(fn LIST)") + +(defun -fourth-item (list) + "Return the fourth item of LIST, or nil if LIST is too short. + +See also: `-fifth-item'." + (declare (pure t) (side-effect-free t)) + (car (cdr (cdr (cdr list))))) + +(defun -fifth-item (list) + "Return the fifth item of LIST, or nil if LIST is too short. + +See also: `-last-item'." + (declare (pure t) (side-effect-free t)) + (car (cdr (cdr (cdr (cdr list)))))) + +(defun -last-item (list) + "Return the last item of LIST, or nil on an empty list." + (declare (pure t) (side-effect-free t)) + (car (last list))) + +;; Use `with-no-warnings' to suppress unbound `-last-item' or +;; undefined `gv--defsetter' warnings arising from both +;; `gv-define-setter' and `defsetf' in certain Emacs versions. +(with-no-warnings + (if (fboundp 'gv-define-setter) + (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val)) + (defsetf -last-item (x) (val) `(setcar (last ,x) ,val)))) + +(defun -butlast (list) + "Return a list of all items in list except for the last." + ;; no alias as we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list)) + +(defmacro --count (pred list) + "Anaphoric form of `-count'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let ((,r 0)) + (--each ,list (when ,pred (setq ,r (1+ ,r)))) + ,r))) + +(defun -count (pred list) + "Counts the number of items in LIST where (PRED item) is non-nil." + (--count (funcall pred it) list)) + +(defun ---truthy? (val) + (declare (pure t) (side-effect-free t)) + (not (null val))) + +(defmacro --any? (form list) + "Anaphoric form of `-any?'." + (declare (debug (form form))) + `(---truthy? (--some ,form ,list))) + +(defun -any? (pred list) + "Return t if (PRED x) is non-nil for any x in LIST, else nil. + +Alias: `-any-p', `-some?', `-some-p'" + (--any? (funcall pred it) list)) + +(defalias '-some? '-any?) +(defalias '--some? '--any?) +(defalias '-any-p '-any?) +(defalias '--any-p '--any?) +(defalias '-some-p '-any?) +(defalias '--some-p '--any?) + +(defmacro --all? (form list) + "Anaphoric form of `-all?'." + (declare (debug (form form))) + (let ((a (make-symbol "all"))) + `(let ((,a t)) + (--each-while ,list ,a (setq ,a ,form)) + (---truthy? ,a)))) + +(defun -all? (pred list) + "Return t if (PRED x) is non-nil for all x in LIST, else nil. + +Alias: `-all-p', `-every?', `-every-p'" + (--all? (funcall pred it) list)) + +(defalias '-every? '-all?) +(defalias '--every? '--all?) +(defalias '-all-p '-all?) +(defalias '--all-p '--all?) +(defalias '-every-p '-all?) +(defalias '--every-p '--all?) + +(defmacro --none? (form list) + "Anaphoric form of `-none?'." + (declare (debug (form form))) + `(--all? (not ,form) ,list)) + +(defun -none? (pred list) + "Return t if (PRED x) is nil for all x in LIST, else nil. + +Alias: `-none-p'" + (--none? (funcall pred it) list)) + +(defalias '-none-p '-none?) +(defalias '--none-p '--none?) + +(defmacro --only-some? (form list) + "Anaphoric form of `-only-some?'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each-while ,list (not (and ,y ,n)) + (if ,form (setq ,y t) (setq ,n t))) + (---truthy? (and ,y ,n))))) + +(defun -only-some? (pred list) + "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED. +Return `nil` both if all items match the predicate or if none of the items match the predicate. + +Alias: `-only-some-p'" + (--only-some? (funcall pred it) list)) + +(defalias '-only-some-p '-only-some?) +(defalias '--only-some-p '--only-some?) + +(defun -slice (list from &optional to step) + "Return copy of LIST, starting from index FROM to index TO. + +FROM or TO may be negative. These values are then interpreted +modulo the length of the list. + +If STEP is a number, only each STEPth item in the resulting +section is returned. Defaults to 1." + (declare (pure t) (side-effect-free t)) + (let ((length (length list)) + (new-list nil)) + ;; to defaults to the end of the list + (setq to (or to length)) + (setq step (or step 1)) + ;; handle negative indices + (when (< from 0) + (setq from (mod from length))) + (when (< to 0) + (setq to (mod to length))) + + ;; iterate through the list, keeping the elements we want + (--each-while list (< it-index to) + (when (and (>= it-index from) + (= (mod (- from it-index) step) 0)) + (push it new-list))) + (nreverse new-list))) + +(defun -take (n list) + "Return a new list of the first N items in LIST, or all items if there are fewer than N. + +See also: `-take-last'" + (declare (pure t) (side-effect-free t)) + (let (result) + (--dotimes n + (when list + (!cons (car list) result) + (!cdr list))) + (nreverse result))) + +(defun -take-last (n list) + "Return the last N items of LIST in order. + +See also: `-take'" + (declare (pure t) (side-effect-free t)) + (copy-sequence (last list n))) + +(defalias '-drop 'nthcdr + "Return the tail of LIST without the first N items. + +See also: `-drop-last' + +\(fn N LIST)") + +(defun -drop-last (n list) + "Remove the last N items of LIST and return a copy. + +See also: `-drop'" + ;; No alias because we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list n)) + +(defmacro --take-while (form list) + "Anaphoric form of `-take-while'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each-while ,list ,form (!cons it ,r)) + (nreverse ,r)))) + +(defun -take-while (pred list) + "Return a new list of successive items from LIST while (PRED item) returns a non-nil value." + (--take-while (funcall pred it) list)) + +(defmacro --drop-while (form list) + "Anaphoric form of `-drop-while'." + (declare (debug (form form))) + (let ((l (make-symbol "list"))) + `(let ((,l ,list)) + (while (and ,l (let ((it (car ,l))) ,form)) + (!cdr ,l)) + ,l))) + +(defun -drop-while (pred list) + "Return the tail of LIST starting from the first item for which (PRED item) returns nil." + (--drop-while (funcall pred it) list)) + +(defun -split-at (n list) + "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list." + (declare (pure t) (side-effect-free t)) + (let (result) + (--dotimes n + (when list + (!cons (car list) result) + (!cdr list))) + (list (nreverse result) list))) + +(defun -rotate (n list) + "Rotate LIST N places to the right. With N negative, rotate to the left. +The time complexity is O(n)." + (declare (pure t) (side-effect-free t)) + (when list + (let* ((len (length list)) + (n-mod-len (mod n len)) + (new-tail-len (- len n-mod-len))) + (append (-drop new-tail-len list) (-take new-tail-len list))))) + +(defun -insert-at (n x list) + "Return a list with X inserted into LIST at position N. + +See also: `-splice', `-splice-list'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cadr split-list))))) + +(defun -replace-at (n x list) + "Return a list with element at Nth position in LIST replaced with X. + +See also: `-replace'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cdr (cadr split-list)))))) + +(defun -update-at (n func list) + "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`. + +See also: `-map-when'" + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list)))))) + +(defmacro --update-at (n form list) + "Anaphoric version of `-update-at'." + (declare (debug (form form form))) + `(-update-at ,n (lambda (it) ,form) ,list)) + +(defun -remove-at (n list) + "Return a list with element at Nth position in LIST removed. + +See also: `-remove-at-indices', `-remove'" + (declare (pure t) (side-effect-free t)) + (-remove-at-indices (list n) list)) + +(defun -remove-at-indices (indices list) + "Return a list whose elements are elements from LIST without +elements selected as `(nth i list)` for all i +from INDICES. + +See also: `-remove-at', `-remove'" + (declare (pure t) (side-effect-free t)) + (let* ((indices (-sort '< indices)) + (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices)))) + r) + (--each diffs + (let ((split (-split-at it list))) + (!cons (car split) r) + (setq list (cdr (cadr split))))) + (!cons list r) + (apply '-concat (nreverse r)))) + +(defmacro --split-with (pred list) + "Anaphoric form of `-split-with'." + (declare (debug (form form))) + (let ((l (make-symbol "list")) + (r (make-symbol "result")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,r nil) + (,c t)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) + (setq ,c nil) + (!cons it ,r) + (!cdr ,l)))) + (list (nreverse ,r) ,l)))) + +(defun -split-with (pred list) + "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list." + (--split-with (funcall pred it) list)) + +(defmacro -split-on (item list) + "Split the LIST each time ITEM is found. + +Unlike `-partition-by', the ITEM is discarded from the results. +Empty lists are also removed from the result. + +Comparison is done by `equal'. + +See also `-split-when'" + (declare (debug (form form))) + `(-split-when (lambda (it) (equal it ,item)) ,list)) + +(defmacro --split-when (form list) + "Anaphoric version of `-split-when'." + (declare (debug (form form))) + `(-split-when (lambda (it) ,form) ,list)) + +(defun -split-when (fn list) + "Split the LIST on each element where FN returns non-nil. + +Unlike `-partition-by', the \"matched\" element is discarded from +the results. Empty lists are also removed from the result. + +This function can be thought of as a generalization of +`split-string'." + (let (r s) + (while list + (if (not (funcall fn (car list))) + (push (car list) s) + (when s (push (nreverse s) r)) + (setq s nil)) + (!cdr list)) + (when s (push (nreverse s) r)) + (nreverse r))) + +(defmacro --separate (form list) + "Anaphoric form of `-separate'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each ,list (if ,form (!cons it ,y) (!cons it ,n))) + (list (nreverse ,y) (nreverse ,n))))) + +(defun -separate (pred list) + "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list." + (--separate (funcall pred it) list)) + +(defun ---partition-all-in-steps-reversed (n step list) + "Private: Used by -partition-all-in-steps and -partition-in-steps." + (when (< step 1) + (error "Step must be a positive number, or you're looking at some juicy infinite loops.")) + (let ((result nil)) + (while list + (!cons (-take n list) result) + (setq list (-drop step list))) + result)) + +(defun -partition-all-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +The last groups may contain less than N items." + (declare (pure t) (side-effect-free t)) + (nreverse (---partition-all-in-steps-reversed n step list))) + +(defun -partition-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (let ((result (---partition-all-in-steps-reversed n step list))) + (while (and result (< (length (car result)) n)) + (!cdr result)) + (nreverse result))) + +(defun -partition-all (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +The last group may contain less than N items." + (declare (pure t) (side-effect-free t)) + (-partition-all-in-steps n n list)) + +(defun -partition (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (-partition-in-steps n n list)) + +(defmacro --partition-by (form list) + "Anaphoric form of `-partition-by'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (v (make-symbol "value")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,v ,form) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (unless (equal ,v ,n) + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,v ,n)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by (fn list) + "Apply FN to each item in LIST, splitting it each time FN returns a new value." + (--partition-by (funcall fn it) list)) + +(defmacro --partition-by-header (form list) + "Anaphoric form of `-partition-by-header'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (h (make-symbol "header-value")) + (b (make-symbol "seen-body?")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,h ,form) + (,b nil) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (if (equal ,h ,n) + (when ,b + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,b nil)) + (setq ,b t)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by-header (fn list) + "Apply FN to the first item in LIST. That is the header +value. Apply FN to each item in LIST, splitting it each time FN +returns the header value, but only after seeing at least one +other value (the body)." + (--partition-by-header (funcall fn it) list)) + +(defun -partition-after-pred (pred list) + "Partition directly after each time PRED is true on an element of LIST." + (when list + (let ((rest (-partition-after-pred pred + (cdr list)))) + (if (funcall pred (car list)) + ;;split after (car list) + (cons (list (car list)) + rest) + + ;;don't split after (car list) + (cons (cons (car list) + (car rest)) + (cdr rest)))))) + +(defun -partition-before-pred (pred list) + "Partition directly before each time PRED is true on an element of LIST." + (nreverse (-map #'reverse + (-partition-after-pred pred (reverse list))))) + +(defun -partition-after-item (item list) + "Partition directly after each time ITEM appears in LIST." + (-partition-after-pred (lambda (ele) (equal ele item)) + list)) + +(defun -partition-before-item (item list) + "Partition directly before each time ITEM appears in LIST." + (-partition-before-pred (lambda (ele) (equal ele item)) + list)) + +(defmacro --group-by (form list) + "Anaphoric form of `-group-by'." + (declare (debug t)) + (let ((n (make-symbol "n")) + (k (make-symbol "k")) + (grp (make-symbol "grp"))) + `(nreverse + (-map + (lambda (,n) + (cons (car ,n) + (nreverse (cdr ,n)))) + (--reduce-from + (let* ((,k (,@form)) + (,grp (assoc ,k acc))) + (if ,grp + (setcdr ,grp (cons it (cdr ,grp))) + (push + (list ,k it) + acc)) + acc) + nil ,list))))) + +(defun -group-by (fn list) + "Separate LIST into an alist whose keys are FN applied to the +elements of LIST. Keys are compared by `equal'." + (--group-by (funcall fn it) list)) + +(defun -interpose (sep list) + "Return a new list of all elements in LIST separated by SEP." + (declare (pure t) (side-effect-free t)) + (let (result) + (when list + (!cons (car list) result) + (!cdr list)) + (while list + (setq result (cons (car list) (cons sep result))) + (!cdr list)) + (nreverse result))) + +(defun -interleave (&rest lists) + "Return a new list of the first item in each list, then the second etc." + (declare (pure t) (side-effect-free t)) + (when lists + (let (result) + (while (-none? 'null lists) + (--each lists (!cons (car it) result)) + (setq lists (-map 'cdr lists))) + (nreverse result)))) + +(defmacro --zip-with (form list1 list2) + "Anaphoric form of `-zip-with'. + +The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'." + (declare (debug (form form form))) + (let ((r (make-symbol "result")) + (l1 (make-symbol "list1")) + (l2 (make-symbol "list2"))) + `(let ((,r nil) + (,l1 ,list1) + (,l2 ,list2)) + (while (and ,l1 ,l2) + (let ((it (car ,l1)) + (other (car ,l2))) + (!cons ,form ,r) + (!cdr ,l1) + (!cdr ,l2))) + (nreverse ,r)))) + +(defun -zip-with (fn list1 list2) + "Zip the two lists LIST1 and LIST2 using a function FN. This +function is applied pairwise taking as first argument element of +LIST1 and as second argument element of LIST2 at corresponding +position. + +The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it', +and the elements from LIST2 as symbol `other'." + (--zip-with (funcall fn it other) list1 list2)) + +(defun -zip (&rest lists) + "Zip LISTS together. Group the head of each list, followed by the +second elements of each list, and so on. The lengths of the returned +groupings are equal to the length of the shortest input list. + +If two lists are provided as arguments, return the groupings as a list +of cons cells. Otherwise, return the groupings as a list of lists. + +Please note! This distinction is being removed in an upcoming 3.0 +release of Dash. If you rely on this behavior, use -zip-pair instead." + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (-none? 'null lists) + (setq results (cons (mapcar 'car lists) results)) + (setq lists (mapcar 'cdr lists))) + (setq results (nreverse results)) + (if (= (length lists) 2) + ;; to support backward compatability, return + ;; a cons cell if two lists were provided + (--map (cons (car it) (cadr it)) results) + results)))) + +(defalias '-zip-pair '-zip) + +(defun -zip-fill (fill-value &rest lists) + "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The +lengths of the returned groupings are equal to the length of the +longest input list." + (declare (pure t) (side-effect-free t)) + (apply '-zip (apply '-pad (cons fill-value lists)))) + +(defun -unzip (lists) + "Unzip LISTS. + +This works just like `-zip' but takes a list of lists instead of +a variable number of arguments, such that + + (-unzip (-zip L1 L2 L3 ...)) + +is identity (given that the lists are the same length). + +See also: `-zip'" + (apply '-zip lists)) + +(defun -cycle (list) + "Return an infinite copy of LIST that will cycle through the +elements and repeat from the beginning." + (declare (pure t) (side-effect-free t)) + (let ((newlist (-map 'identity list))) + (nconc newlist newlist))) + +(defun -pad (fill-value &rest lists) + "Appends FILL-VALUE to the end of each list in LISTS such that they +will all have the same length." + (let* ((annotations (-annotate 'length lists)) + (n (-max (-map 'car annotations)))) + (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations))) + +(defun -annotate (fn list) + "Return a list of cons cells where each cell is FN applied to each +element of LIST paired with the unmodified element of LIST." + (-zip (-map fn list) list)) + +(defmacro --annotate (form list) + "Anaphoric version of `-annotate'." + (declare (debug (form form))) + `(-annotate (lambda (it) ,form) ,list)) + +(defun dash--table-carry (lists restore-lists &optional re) + "Helper for `-table' and `-table-flat'. + +If a list overflows, carry to the right and reset the list." + (while (not (or (car lists) + (equal lists '(nil)))) + (setcar lists (car restore-lists)) + (pop (cadr lists)) + (!cdr lists) + (!cdr restore-lists) + (when re + (push (nreverse (car re)) (cadr re)) + (setcar re nil) + (!cdr re)))) + +(defun -table (fn &rest lists) + "Compute outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The dimension of the result is (length lists). + +See also: `-table-flat'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + (re (make-list (length lists) nil))) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item (car re)) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists re))) + (nreverse (car (last re))))) + +(defun -table-flat (fn &rest lists) + "Compute flat outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The results are flattened, ignoring the tensor structure +of the result. This is equivalent to calling: + + (-flatten-n (1- (length lists)) (apply \\='-table fn lists)) + +but the implementation here is much more efficient. + +See also: `-flatten-n', `-table'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + re) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item re) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists))) + (nreverse re))) + +(defun -partial (fn &rest args) + "Take a function FN and fewer than the normal arguments to FN, +and return a fn that takes a variable number of additional ARGS. +When called, the returned function calls FN with ARGS first and +then additional args." + (apply 'apply-partially fn args)) + +(defun -elem-index (elem list) + "Return the index of the first element in the given LIST which +is equal to the query element ELEM, or nil if there is no +such element." + (declare (pure t) (side-effect-free t)) + (car (-elem-indices elem list))) + +(defun -elem-indices (elem list) + "Return the indices of all elements in LIST equal to the query +element ELEM, in ascending order." + (declare (pure t) (side-effect-free t)) + (-find-indices (-partial 'equal elem) list)) + +(defun -find-indices (pred list) + "Return the indices of all elements in LIST satisfying the +predicate PRED, in ascending order." + (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list))) + +(defmacro --find-indices (form list) + "Anaphoric version of `-find-indices'." + (declare (debug (form form))) + `(-find-indices (lambda (it) ,form) ,list)) + +(defun -find-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +first element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-first'." + (car (-find-indices pred list))) + +(defmacro --find-index (form list) + "Anaphoric version of `-find-index'." + (declare (debug (form form))) + `(-find-index (lambda (it) ,form) ,list)) + +(defun -find-last-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +last element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-last'." + (-last-item (-find-indices pred list))) + +(defmacro --find-last-index (form list) + "Anaphoric version of `-find-last-index'." + `(-find-last-index (lambda (it) ,form) ,list)) + +(defun -select-by-indices (indices list) + "Return a list whose elements are elements from LIST selected +as `(nth i list)` for all i from INDICES." + (declare (pure t) (side-effect-free t)) + (let (r) + (--each indices + (!cons (nth it list) r)) + (nreverse r))) + +(defun -select-columns (columns table) + "Select COLUMNS from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +Each row is transformed such that only the specified COLUMNS are +selected. + +See also: `-select-column', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--map (-select-by-indices columns it) table)) + +(defun -select-column (column table) + "Select COLUMN from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +The single selected column is returned as a list. + +See also: `-select-columns', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--mapcat (-select-by-indices (list column) it) table)) + +(defmacro -> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the second item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +second item in second form, etc." + (declare (debug (form &rest [&or symbolp (sexp &rest form)]))) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,(car form) ,x ,@(cdr form)) + (list form x))) + (:else `(-> (-> ,x ,form) ,@more)))) + +(defmacro ->> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the last item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +last item in second form, etc." + (declare (debug ->)) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,@form ,x) + (list form x))) + (:else `(->> (->> ,x ,form) ,@more)))) + +(defmacro --> (x &rest forms) + "Starting with the value of X, thread each expression through FORMS. + +Insert X at the position signified by the symbol `it' in the first +form. If there are more forms, insert the first form at the position +signified by `it' in in second form, etc." + (declare (debug (form body))) + `(-as-> ,x it ,@forms)) + +(defmacro -as-> (value variable &rest forms) + "Starting with VALUE, thread VARIABLE through FORMS. + +In the first form, bind VARIABLE to VALUE. In the second form, bind +VARIABLE to the result of the first form, and so forth." + (declare (debug (form symbolp body))) + (if (null forms) + `,value + `(let ((,variable ,value)) + (-as-> ,(if (symbolp (car forms)) + (list (car forms) variable) + (car forms)) + ,variable + ,@(cdr forms))))) + +(defmacro -some-> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some-> (-when-let (,result ,x) + (-> ,result ,form)) + ,@more)))) + +(defmacro -some->> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->>'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some->> (-when-let (,result ,x) + (->> ,result ,form)) + ,@more)))) + +(defmacro -some--> (x &optional form &rest more) + "When expr in non-nil, thread it through the first form (via `-->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some--> (-when-let (,result ,x) + (--> ,result ,form)) + ,@more)))) + +(defun -grade-up (comparator list) + "Grade elements of LIST using COMPARATOR relation, yielding a +permutation vector such that applying this permutation to LIST +sorts it in ascending order." + ;; ugly hack to "fix" lack of lexical scope + (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other))))) + (->> (--map-indexed (cons it it-index) list) + (-sort comp) + (-map 'cdr)))) + +(defun -grade-down (comparator list) + "Grade elements of LIST using COMPARATOR relation, yielding a +permutation vector such that applying this permutation to LIST +sorts it in descending order." + ;; ugly hack to "fix" lack of lexical scope + (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it))))) + (->> (--map-indexed (cons it it-index) list) + (-sort comp) + (-map 'cdr)))) + +(defvar dash--source-counter 0 + "Monotonic counter for generated symbols.") + +(defun dash--match-make-source-symbol () + "Generate a new dash-source symbol. + +All returned symbols are guaranteed to be unique." + (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter)) + (setq dash--source-counter (1+ dash--source-counter)))) + +(defun dash--match-ignore-place-p (symbol) + "Return non-nil if SYMBOL is a symbol and starts with _." + (and (symbolp symbol) + (eq (aref (symbol-name symbol) 0) ?_))) + +(defun dash--match-cons-skip-cdr (skip-cdr source) + "Helper function generating idiomatic shifting code." + (cond + ((= skip-cdr 0) + `(pop ,source)) + (t + `(prog1 ,(dash--match-cons-get-car skip-cdr source) + (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source)))))) + +(defun dash--match-cons-get-car (skip-cdr source) + "Helper function generating idiomatic code to get nth car." + (cond + ((= skip-cdr 0) + `(car ,source)) + ((= skip-cdr 1) + `(cadr ,source)) + (t + `(nth ,skip-cdr ,source)))) + +(defun dash--match-cons-get-cdr (skip-cdr source) + "Helper function generating idiomatic code to get nth cdr." + (cond + ((= skip-cdr 0) + source) + ((= skip-cdr 1) + `(cdr ,source)) + (t + `(nthcdr ,skip-cdr ,source)))) + +(defun dash--match-cons (match-form source) + "Setup a cons matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol)) + (n 0) + (m match-form)) + (while (and (consp m) + (dash--match-ignore-place-p (car m))) + (setq n (1+ n)) (!cdr m)) + (cond + ;; when we only have one pattern in the list, we don't have to + ;; create a temporary binding (--dash-source--) for the source + ;; and just use the input directly + ((and (consp m) + (not (cdr m))) + (dash--match (car m) (dash--match-cons-get-car n source))) + ;; handle other special types + ((> n 0) + (dash--match m (dash--match-cons-get-cdr n source))) + ;; this is the only entry-point for dash--match-cons-1, that's + ;; why we can't simply use the above branch, it would produce + ;; infinite recursion + (t + (cons (list s source) (dash--match-cons-1 match-form s)))))) + +(defun dash--get-expand-function (type) + "Get expand function name for TYPE." + (intern-soft (format "dash-expand:%s" type))) + +(defun dash--match-cons-1 (match-form source &optional props) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a proper or improper list. Each element of +MATCH-FORM is either a symbol, which gets bound to the respective +value in source or another match form which gets destructured +recursively. + +If the cdr of last cons cell in the list is `nil', matching stops +there. + +SOURCE is a proper or improper list." + (let ((skip-cdr (or (plist-get props :skip-cdr) 0))) + (cond + ((consp match-form) + (cond + ((cdr match-form) + (cond + ((and (symbolp (car match-form)) + (functionp (dash--get-expand-function (car match-form)))) + (dash--match-kv (dash--match-kv-normalize-match-form match-form) (dash--match-cons-get-cdr skip-cdr source))) + ((dash--match-ignore-place-p (car match-form)) + (dash--match-cons-1 (cdr match-form) source + (plist-put props :skip-cdr (1+ skip-cdr)))) + (t + (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source)) + (dash--match-cons-1 (cdr match-form) source))))) + (t ;; Last matching place, no need for shift + (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source))))) + ((eq match-form nil) + nil) + (t ;; Handle improper lists. Last matching place, no need for shift + (dash--match match-form (dash--match-cons-get-cdr skip-cdr source)))))) + +(defun dash--vector-tail (seq start) + "Return the tail of SEQ starting at START." + (cond + ((vectorp seq) + (let* ((re-length (- (length seq) start)) + (re (make-vector re-length 0))) + (--dotimes re-length (aset re it (aref seq (+ it start)))) + re)) + ((stringp seq) + (substring seq start)))) + +(defun dash--match-vector (match-form source) + "Setup a vector matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern + ((= (length match-form) 1) + (dash--match (aref match-form 0) `(aref ,source 0))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-vector-1 match-form source)) + ;; don't bind `s' if we only have one sub-pattern which is not ignored + ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form)) + (ignored-places-n (length (-remove 'null ignored-places)))) + (when (= ignored-places-n (1- (length match-form))) + (let ((n (-find-index 'null ignored-places))) + (dash--match (aref match-form n) `(aref ,source ,n)))))) + (t + (cons (list s source) (dash--match-vector-1 match-form s)))))) + +(defun dash--match-vector-1 (match-form source) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a vector. Each element of MATCH-FORM is either a +symbol, which gets bound to the respective value in source or +another match form which gets destructured recursively. + +If second-from-last place in MATCH-FORM is the symbol &rest, the +next element of the MATCH-FORM is matched against the tail of +SOURCE, starting at index of the &rest symbol. This is +conceptually the same as the (head . tail) match for improper +lists, where dot plays the role of &rest. + +SOURCE is a vector. + +If the MATCH-FORM vector is shorter than SOURCE vector, only +the (length MATCH-FORM) places are bound, the rest of the SOURCE +is discarded." + (let ((i 0) + (l (length match-form)) + (re)) + (while (< i l) + (let ((m (aref match-form i))) + (push (cond + ((and (symbolp m) + (eq m '&rest)) + (prog1 (dash--match + (aref match-form (1+ i)) + `(dash--vector-tail ,source ,i)) + (setq i l))) + ((and (symbolp m) + ;; do not match symbols starting with _ + (not (eq (aref (symbol-name m) 0) ?_))) + (list (list m `(aref ,source ,i)))) + ((not (symbolp m)) + (dash--match m `(aref ,source ,i)))) + re) + (setq i (1+ i)))) + (-flatten-n 1 (nreverse re)))) + +(defun dash--match-kv-normalize-match-form (pattern) + "Normalize kv PATTERN. + +This method normalizes PATTERN to the format expected by +`dash--match-kv'. See `-let' for the specification." + (let ((normalized (list (car pattern))) + (skip nil) + (fill-placeholder (make-symbol "--dash-fill-placeholder--"))) + (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern))) + (lambda (pair) + (let ((current (car pair)) + (next (cdr pair))) + (if skip + (setq skip nil) + (if (or (eq fill-placeholder next) + (not (or (and (symbolp next) + (not (keywordp next)) + (not (eq next t)) + (not (eq next nil))) + (and (consp next) + (not (eq (car next) 'quote))) + (vectorp next)))) + (progn + (cond + ((keywordp current) + (push current normalized) + (push (intern (substring (symbol-name current) 1)) normalized)) + ((stringp current) + (push current normalized) + (push (intern current) normalized)) + ((and (consp current) + (eq (car current) 'quote)) + (push current normalized) + (push (cadr current) normalized)) + (t (error "-let: found key `%s' in kv destructuring but its pattern `%s' is invalid and can not be derived from the key" current next))) + (setq skip nil)) + (push current normalized) + (push next normalized) + (setq skip t)))))) + (nreverse normalized))) + +(defun dash--match-kv (match-form source) + "Setup a kv matching environment and call the real matcher. + +kv can be any key-value store, such as plist, alist or hash-table." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern (&type key val) + ((= (length match-form) 3) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + (t + (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form))))))) + +(defun dash-expand:&hash (key source) + "Generate extracting KEY from SOURCE for &hash destructuring." + `(gethash ,key ,source)) + +(defun dash-expand:&plist (key source) + "Generate extracting KEY from SOURCE for &plist destructuring." + `(plist-get ,source ,key)) + +(defun dash-expand:&alist (key source) + "Generate extracting KEY from SOURCE for &alist destructuring." + `(cdr (assoc ,key ,source))) + +(defun dash-expand:&hash? (key source) + "Generate extracting KEY from SOURCE for &hash? destructuring. +Similar to &hash but check whether the map is not nil." + (let ((src (make-symbol "src"))) + `(let ((,src ,source)) + (when ,src (gethash ,key ,src))))) + +(defalias 'dash-expand:&keys 'dash-expand:&plist) + +(defun dash--match-kv-1 (match-form source type) + "Match MATCH-FORM against SOURCE of type TYPE. + +MATCH-FORM is a proper list of the form (key1 place1 ... keyN +placeN). Each placeK is either a symbol, which gets bound to the +value of keyK retrieved from the key-value store, or another +match form which gets destructured recursively. + +SOURCE is a key-value store of type TYPE, which can be a plist, +an alist or a hash table. + +TYPE is a token specifying the type of the key-value store. +Valid values are &plist, &alist and &hash." + (-flatten-n 1 (-map + (lambda (kv) + (let* ((k (car kv)) + (v (cadr kv)) + (getter + (funcall (dash--get-expand-function type) k source))) + (cond + ((symbolp v) + (list (list v getter))) + (t (dash--match v getter))))) + (-partition 2 match-form)))) + +(defun dash--match-symbol (match-form source) + "Bind a symbol. + +This works just like `let', there is no destructuring." + (list (list match-form source))) + +(defun dash--match (match-form source) + "Match MATCH-FORM against SOURCE. + +This function tests the MATCH-FORM and dispatches to specific +matchers based on the type of the expression. + +Key-value stores are disambiguated by placing a token &plist, +&alist or &hash as a first item in the MATCH-FORM." + (cond + ((symbolp match-form) + (dash--match-symbol match-form source)) + ((consp match-form) + (cond + ;; Handle the "x &as" bindings first. + ((and (consp (cdr match-form)) + (symbolp (car match-form)) + (eq '&as (cadr match-form))) + (let ((s (car match-form))) + (cons (list s source) + (dash--match (cddr match-form) s)))) + ((functionp (dash--get-expand-function (car match-form))) + (dash--match-kv (dash--match-kv-normalize-match-form match-form) source)) + (t (dash--match-cons match-form source)))) + ((vectorp match-form) + ;; We support the &as binding in vectors too + (cond + ((and (> (length match-form) 2) + (symbolp (aref match-form 0)) + (eq '&as (aref match-form 1))) + (let ((s (aref match-form 0))) + (cons (list s source) + (dash--match (dash--vector-tail match-form 2) s)))) + (t (dash--match-vector match-form source)))))) + +(defun dash--normalize-let-varlist (varlist) + "Normalize VARLIST so that every binding is a list. + +`let' allows specifying a binding which is not a list but simply +the place which is then automatically bound to nil, such that all +three of the following are identical and evaluate to nil. + + (let (a) a) + (let ((a)) a) + (let ((a nil)) a) + +This function normalizes all of these to the last form." + (--map (if (consp it) it (list it nil)) varlist)) + +(defmacro -let* (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE structurally. SOURCE is +only evaluated once for each PATTERN. + +Each SOURCE can refer to the symbols already bound by this +VARLIST. This is useful if you want to destructure SOURCE +recursively but also want to name the intermediate structures. + +See `-let' for the list of all possible patterns." + (declare (debug ((&rest [&or (sexp form) sexp]) body)) + (indent 1)) + (let* ((varlist (dash--normalize-let-varlist varlist)) + (bindings (--mapcat (dash--match (car it) (cadr it)) varlist))) + `(let* ,bindings + ,@body))) + +(defmacro -let (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE \"structurally\". SOURCE +is only evaluated once for each PATTERN. Each PATTERN is matched +recursively, and can therefore contain sub-patterns which are +matched against corresponding sub-expressions of SOURCE. + +All the SOURCEs are evalled before any symbols are +bound (i.e. \"in parallel\"). + +If VARLIST only contains one (PATTERN SOURCE) element, you can +optionally specify it using a vector and discarding the +outer-most parens. Thus + + (-let ((PATTERN SOURCE)) ..) + +becomes + + (-let [PATTERN SOURCE] ..). + +`-let' uses a convention of not binding places (symbols) starting +with _ whenever it's possible. You can use this to skip over +entries you don't care about. However, this is not *always* +possible (as a result of implementation) and these symbols might +get bound to undefined values. + +Following is the overview of supported patterns. Remember that +patterns can be matched recursively, so every a, b, aK in the +following can be a matching construct and not necessarily a +symbol/variable. + +Symbol: + + a - bind the SOURCE to A. This is just like regular `let'. + +Conses and lists: + + (a) - bind `car' of cons/list to A + + (a . b) - bind car of cons to A and `cdr' to B + + (a b) - bind car of list to A and `cadr' to B + + (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ... + + (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST. + +Vectors: + + [a] - bind 0th element of a non-list sequence to A (works with + vectors, strings, bit arrays...) + + [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to + A1, 2nd to A2, ... + If the PATTERN is shorter than SOURCE, the values at + places not in PATTERN are ignored. + If the PATTERN is longer than SOURCE, an `error' is + thrown. + + [a1 a2 a3 ... &rest rest] - as above, but bind the rest of + the sequence to REST. This is + conceptually the same as improper list + matching (a1 a2 ... aN . rest) + +Key/value stores: + + (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE plist to aK. If the + value is not found, aK is nil. + Uses `plist-get' to fetch values. + + (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE alist to aK. If the + value is not found, aK is nil. + Uses `assoc' to fetch values. + + (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE hash table to aK. If the + value is not found, aK is nil. + Uses `gethash' to fetch values. + +Further, special keyword &keys supports \"inline\" matching of +plist-like key-value pairs, similarly to &keys keyword of +`cl-defun'. + + (a1 a2 ... aN &keys key1 b1 ... keyN bK) + +This binds N values from the list to a1 ... aN, then interprets +the cdr as a plist (see key/value matching above). + +A shorthand notation for kv-destructuring exists which allows the +patterns be optionally left out and derived from the key name in +the following fashion: + +- a key :foo is converted into `foo' pattern, +- a key 'bar is converted into `bar' pattern, +- a key \"baz\" is converted into `baz' pattern. + +That is, the entire value under the key is bound to the derived +variable without any further destructuring. + +This is possible only when the form following the key is not a +valid pattern (i.e. not a symbol, a cons cell or a vector). +Otherwise the matching proceeds as usual and in case of an +invalid spec fails with an error. + +Thus the patterns are normalized as follows: + + ;; derive all the missing patterns + (&plist :foo 'bar \"baz\") => (&plist :foo foo 'bar bar \"baz\" baz) + + ;; we can specify some but not others + (&plist :foo 'bar explicit-bar) => (&plist :foo foo 'bar explicit-bar) + + ;; nothing happens, we store :foo in x + (&plist :foo x) => (&plist :foo x) + + ;; nothing happens, we match recursively + (&plist :foo (a b c)) => (&plist :foo (a b c)) + +You can name the source using the syntax SYMBOL &as PATTERN. +This syntax works with lists (proper or improper), vectors and +all types of maps. + + (list &as a b c) (list 1 2 3) + +binds A to 1, B to 2, C to 3 and LIST to (1 2 3). + +Similarly: + + (bounds &as beg . end) (cons 1 2) + +binds BEG to 1, END to 2 and BOUNDS to (1 . 2). + + (items &as first . rest) (list 1 2 3) + +binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3) + + [vect &as _ b c] [1 2 3] + +binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual). + + (plist &as &plist :b b) (list :a 1 :b 2 :c 3) + +binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash. + +This is especially useful when we want to capture the result of a +computation and destructure at the same time. Consider the +form (function-returning-complex-structure) returning a list of +two vectors with two items each. We want to capture this entire +result and pass it to another computation, but at the same time +we want to get the second item from each vector. We can achieve +it with pattern + + (result &as [_ a] [_ b]) (function-returning-complex-structure) + +Note: Clojure programmers may know this feature as the \":as +binding\". The difference is that we put the &as at the front +because we need to support improper list binding." + (declare (debug ([&or (&rest [&or (sexp form) sexp]) + (vector [&rest [sexp form]])] + body)) + (indent 1)) + (if (vectorp varlist) + `(let* ,(dash--match (aref varlist 0) (aref varlist 1)) + ,@body) + (let* ((varlist (dash--normalize-let-varlist varlist)) + (inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist)) + (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs)))) + `(let ,inputs + (-let* ,new-varlist ,@body))))) + +(defmacro -lambda (match-form &rest body) + "Return a lambda which destructures its input as MATCH-FORM and executes BODY. + +Note that you have to enclose the MATCH-FORM in a pair of parens, +such that: + + (-lambda (x) body) + (-lambda (x y ...) body) + +has the usual semantics of `lambda'. Furthermore, these get +translated into normal lambda, so there is no performance +penalty. + +See `-let' for the description of destructuring mechanism." + (declare (doc-string 2) (indent defun) + (debug (&define sexp + [&optional stringp] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((not (consp match-form)) + (signal 'wrong-type-argument "match-form must be a list")) + ;; no destructuring, so just return regular lambda to make things faster + ((-all? 'symbolp match-form) + `(lambda ,match-form ,@body)) + (t + (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form))) + ;; TODO: because inputs to the lambda are evaluated only once, + ;; -let* need not to create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(lambda ,(--map (cadr it) inputs) + (-let* ,inputs ,@body)))))) + +(defmacro -setq (&rest forms) + "Bind each MATCH-FORM to the value of its VAL. + +MATCH-FORM destructuring is done according to the rules of `-let'. + +This macro allows you to bind multiple variables by destructuring +the value, so for example: + + (-setq (a b) x + (&plist :c c) plist) + +expands roughly speaking to the following code + + (setq a (car x) + b (cadr x) + c (plist-get plist :c)) + +Care is taken to only evaluate each VAL once so that in case of +multiple assignments it does not cause unexpected side effects. + +\(fn [MATCH-FORM VAL]...)" + (declare (debug (&rest sexp form)) + (indent 1)) + (when (= (mod (length forms) 2) 1) + (error "Odd number of arguments")) + (let* ((forms-and-sources + ;; First get all the necessary mappings with all the + ;; intermediate bindings. + (-map (lambda (x) (dash--match (car x) (cadr x))) + (-partition 2 forms))) + ;; To preserve the logic of dynamic scoping we must ensure + ;; that we `setq' the variables outside of the `let*' form + ;; which holds the destructured intermediate values. For + ;; this we generate for each variable a placeholder which is + ;; bound to (lexically) the result of the destructuring. + ;; Then outside of the helper `let*' form we bind all the + ;; original variables to their respective placeholders. + ;; TODO: There is a lot of room for possible optimization, + ;; for start playing with `special-variable-p' to eliminate + ;; unnecessary re-binding. + (variables-to-placeholders + (-mapcat + (lambda (bindings) + (-map + (lambda (binding) + (let ((var (car binding))) + (list var (make-symbol (concat "--dash-binding-" (symbol-name var) "--"))))) + (--filter (not (string-prefix-p "--" (symbol-name (car it)))) bindings))) + forms-and-sources))) + `(let ,(-map 'cadr variables-to-placeholders) + (let* ,(-flatten-n 1 forms-and-sources) + (setq ,@(-flatten (-map 'reverse variables-to-placeholders)))) + (setq ,@(-flatten variables-to-placeholders))))) + +(defmacro -if-let* (vars-vals then &rest else) + "If all VALS evaluate to true, bind them to their corresponding +VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list +of (VAR VAL) pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) form body)) + (indent 2)) + (->> vars-vals + (--mapcat (dash--match (car it) (cadr it))) + (--reduce-r-from + (let ((var (car it)) + (val (cadr it))) + `(let ((,var ,val)) + (if ,var ,acc ,@else))) + then))) + +(defmacro -if-let (var-val then &rest else) + "If VAL evaluates to non-nil, bind it to VAR and do THEN, +otherwise do ELSE. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) THEN &rest ELSE)" + (declare (debug ((sexp form) form body)) + (indent 2)) + `(-if-let* (,var-val) ,then ,@else)) + +(defmacro --if-let (val then &rest else) + "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN, +otherwise do ELSE." + (declare (debug (form form body)) + (indent 2)) + `(-if-let (it ,val) ,then ,@else)) + +(defmacro -when-let* (vars-vals &rest body) + "If all VALS evaluate to true, bind them to their corresponding +VARS and execute body. VARS-VALS should be a list of (VAR VAL) +pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) body)) + (indent 1)) + `(-if-let* ,vars-vals (progn ,@body))) + +(defmacro -when-let (var-val &rest body) + "If VAL evaluates to non-nil, bind it to VAR and execute body. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) &rest BODY)" + (declare (debug ((sexp form) body)) + (indent 1)) + `(-if-let ,var-val (progn ,@body))) + +(defmacro --when-let (val &rest body) + "If VAL evaluates to non-nil, bind it to symbol `it' and +execute body." + (declare (debug (form body)) + (indent 1)) + `(--if-let ,val (progn ,@body))) + +(defvar -compare-fn nil + "Tests for equality use this function or `equal' if this is nil. +It should only be set using dynamic scope with a let, like: + + (let ((-compare-fn #\\='=)) (-union numbers1 numbers2 numbers3)") + +(defun -distinct (list) + "Return a new list with all duplicates removed. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil. + +Alias: `-uniq'" + ;; Implementation note: The speedup gained from hash table lookup + ;; starts to outweigh its overhead for lists of length greater than + ;; 32. See discussion in PR #305. + (let* ((len (length list)) + (lut (and (> len 32) + ;; Check that `-compare-fn' is a valid hash-table + ;; lookup function or `nil'. + (memq -compare-fn '(nil equal eq eql)) + (make-hash-table :test (or -compare-fn #'equal) + :size len)))) + (if lut + (--filter (unless (gethash it lut) + (puthash it t lut)) + list) + (--each list (unless (-contains? lut it) (!cons it lut))) + (nreverse lut)))) + +(defalias '-uniq '-distinct) + +(defun -union (list list2) + "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + ;; We fall back to iteration implementation if the comparison + ;; function isn't one of `eq', `eql' or `equal'. + (let* ((result (reverse list)) + ;; TODO: get rid of this dynamic variable, pass it as an + ;; argument instead. + (-compare-fn (if (bound-and-true-p -compare-fn) + -compare-fn + 'equal))) + (if (memq -compare-fn '(eq eql equal)) + (let ((ht (make-hash-table :test -compare-fn))) + (--each list (puthash it t ht)) + (--each list2 (unless (gethash it ht) (!cons it result)))) + (--each list2 (unless (-contains? result it) (!cons it result)))) + (nreverse result))) + +(defun -intersection (list list2) + "Return a new list containing only the elements that are members of both LIST and LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (-contains? list2 it) list)) + +(defun -difference (list list2) + "Return a new list with only the members of LIST that are not in LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (not (-contains? list2 it)) list)) + +(defun -powerset (list) + "Return the power set of LIST." + (if (null list) '(()) + (let ((last (-powerset (cdr list)))) + (append (mapcar (lambda (x) (cons (car list) x)) last) + last)))) + +(defun -permutations (list) + "Return the permutations of LIST." + (if (null list) '(()) + (apply #'append + (mapcar (lambda (x) + (mapcar (lambda (perm) (cons x perm)) + (-permutations (remove x list)))) + list)))) + +(defun -inits (list) + "Return all prefixes of LIST." + (let ((res (list list))) + (setq list (reverse list)) + (while list + (push (reverse (!cdr list)) res)) + res)) + +(defun -tails (list) + "Return all suffixes of LIST" + (-reductions-r-from 'cons nil list)) + +(defun -common-prefix (&rest lists) + "Return the longest common prefix of LISTS." + (declare (pure t) (side-effect-free t)) + (--reduce (--take-while (and acc (equal (pop acc) it)) it) + lists)) + +(defun -common-suffix (&rest lists) + "Return the longest common suffix of LISTS." + (nreverse (apply #'-common-prefix (mapcar #'reverse lists)))) + +(defun -contains? (list element) + "Return non-nil if LIST contains ELEMENT. + +The test for equality is done with `equal', or with `-compare-fn' +if that's non-nil. + +Alias: `-contains-p'" + (not + (null + (cond + ((null -compare-fn) (member element list)) + ((eq -compare-fn 'eq) (memq element list)) + ((eq -compare-fn 'eql) (memql element list)) + (t + (let ((lst list)) + (while (and lst + (not (funcall -compare-fn element (car lst)))) + (setq lst (cdr lst))) + lst)))))) + +(defalias '-contains-p '-contains?) + +(defun -same-items? (list list2) + "Return true if LIST and LIST2 has the same items. + +The order of the elements in the lists does not matter. + +Alias: `-same-items-p'" + (let ((length-a (length list)) + (length-b (length list2))) + (and + (= length-a length-b) + (= length-a (length (-intersection list list2)))))) + +(defalias '-same-items-p '-same-items?) + +(defun -is-prefix? (prefix list) + "Return non-nil if PREFIX is prefix of LIST. + +Alias: `-is-prefix-p'" + (declare (pure t) (side-effect-free t)) + (--each-while list (equal (car prefix) it) + (!cdr prefix)) + (not prefix)) + +(defun -is-suffix? (suffix list) + "Return non-nil if SUFFIX is suffix of LIST. + +Alias: `-is-suffix-p'" + (declare (pure t) (side-effect-free t)) + (-is-prefix? (reverse suffix) (reverse list))) + +(defun -is-infix? (infix list) + "Return non-nil if INFIX is infix of LIST. + +This operation runs in O(n^2) time + +Alias: `-is-infix-p'" + (declare (pure t) (side-effect-free t)) + (let (done) + (while (and (not done) list) + (setq done (-is-prefix? infix list)) + (!cdr list)) + done)) + +(defalias '-is-prefix-p '-is-prefix?) +(defalias '-is-suffix-p '-is-suffix?) +(defalias '-is-infix-p '-is-infix?) + +(defun -sort (comparator list) + "Sort LIST, stably, comparing elements using COMPARATOR. +Return the sorted list. LIST is NOT modified by side effects. +COMPARATOR is called with two elements of LIST, and should return non-nil +if the first element should sort before the second." + (sort (copy-sequence list) comparator)) + +(defmacro --sort (form list) + "Anaphoric form of `-sort'." + (declare (debug (form form))) + `(-sort (lambda (it other) ,form) ,list)) + +(defun -list (&rest args) + "Return a list with ARGS. + +If first item of ARGS is already a list, simply return ARGS. If +not, return a list with ARGS as elements." + (declare (pure t) (side-effect-free t)) + (let ((arg (car args))) + (if (listp arg) arg args))) + +(defun -repeat (n x) + "Return a list with X repeated N times. +Return nil if N is less than 1." + (declare (pure t) (side-effect-free t)) + (let (ret) + (--dotimes n (!cons x ret)) + ret)) + +(defun -sum (list) + "Return the sum of LIST." + (declare (pure t) (side-effect-free t)) + (apply '+ list)) + +(defun -running-sum (list) + "Return a list with running sums of items in LIST. + +LIST must be non-empty." + (declare (pure t) (side-effect-free t)) + (unless (consp list) + (error "LIST must be non-empty")) + (-reductions '+ list)) + +(defun -product (list) + "Return the product of LIST." + (declare (pure t) (side-effect-free t)) + (apply '* list)) + +(defun -running-product (list) + "Return a list with running products of items in LIST. + +LIST must be non-empty." + (declare (pure t) (side-effect-free t)) + (unless (consp list) + (error "LIST must be non-empty")) + (-reductions '* list)) + +(defun -max (list) + "Return the largest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'max list)) + +(defun -min (list) + "Return the smallest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'min list)) + +(defun -max-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the greatest element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) it acc) list)) + +(defun -min-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the least element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) acc it) list)) + +(defmacro --max-by (form list) + "Anaphoric version of `-max-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (form form))) + `(-max-by (lambda (it other) ,form) ,list)) + +(defmacro --min-by (form list) + "Anaphoric version of `-min-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (form form))) + `(-min-by (lambda (it other) ,form) ,list)) + +(defun -iterate (fun init n) + "Return a list of iterated applications of FUN to INIT. + +This means a list of form: + + (init (fun init) (fun (fun init)) ...) + +N is the length of the returned list." + (if (= n 0) nil + (let ((r (list init))) + (--dotimes (1- n) + (push (funcall fun (car r)) r)) + (nreverse r)))) + +(defun -fix (fn list) + "Compute the (least) fixpoint of FN with initial input LIST. + +FN is called at least once, results are compared with `equal'." + (let ((re (funcall fn list))) + (while (not (equal list re)) + (setq list re) + (setq re (funcall fn re))) + re)) + +(defmacro --fix (form list) + "Anaphoric form of `-fix'." + `(-fix (lambda (it) ,form) ,list)) + +(defun -unfold (fun seed) + "Build a list from SEED using FUN. + +This is \"dual\" operation to `-reduce-r': while -reduce-r +consumes a list to produce a single value, `-unfold' takes a +seed value and builds a (potentially infinite!) list. + +FUN should return `nil' to stop the generating process, or a +cons (A . B), where A will be prepended to the result and B is +the new seed." + (let ((last (funcall fun seed)) r) + (while last + (push (car last) r) + (setq last (funcall fun (cdr last)))) + (nreverse r))) + +(defmacro --unfold (form seed) + "Anaphoric version of `-unfold'." + (declare (debug (form form))) + `(-unfold (lambda (it) ,form) ,seed)) + +(defun -cons-pair? (con) + "Return non-nil if CON is true cons pair. +That is (A . B) where B is not a list. + +Alias: `-cons-pair-p'" + (declare (pure t) (side-effect-free t)) + (and (listp con) + (not (listp (cdr con))))) + +(defalias '-cons-pair-p '-cons-pair?) + +(defun -cons-to-list (con) + "Convert a cons pair to a list with `car' and `cdr' of the pair respectively." + (declare (pure t) (side-effect-free t)) + (list (car con) (cdr con))) + +(defun -value-to-list (val) + "Convert a value to a list. + +If the value is a cons pair, make a list with two elements, `car' +and `cdr' of the pair respectively. + +If the value is anything else, wrap it in a list." + (declare (pure t) (side-effect-free t)) + (cond + ((-cons-pair? val) (-cons-to-list val)) + (t (list val)))) + +(defun -tree-mapreduce-from (fn folder init-value tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce-from' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce-from (form folder init-value tree) + "Anaphoric form of `-tree-mapreduce-from'." + (declare (debug (form form form form))) + `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree)) + +(defun -tree-mapreduce (fn folder tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce (form folder tree) + "Anaphoric form of `-tree-mapreduce'." + (declare (debug (form form form))) + `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree)) + +(defun -tree-map (fn tree) + "Apply FN to each element of TREE while preserving the tree structure." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (mapcar (lambda (x) (-tree-map fn x)) tree)) + (t (funcall fn tree)))) + +(defmacro --tree-map (form tree) + "Anaphoric form of `-tree-map'." + (declare (debug (form form))) + `(-tree-map (lambda (it) ,form) ,tree)) + +(defun -tree-reduce-from (fn init-value tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to INIT-VALUE and first element of the list, +then on this result and second element from the list etc. + +The initial value is ignored on cons pairs as they always contain +two elements." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree))) + (t tree))) + +(defmacro --tree-reduce-from (form init-value tree) + "Anaphoric form of `-tree-reduce-from'." + (declare (debug (form form form))) + `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree)) + +(defun -tree-reduce (fn tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to first element of the list and second +element, then on this result and third element from the list etc. + +See `-reduce-r' for how exactly are lists of zero or one element handled." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree))) + (t tree))) + +(defmacro --tree-reduce (form tree) + "Anaphoric form of `-tree-reduce'." + (declare (debug (form form))) + `(-tree-reduce (lambda (it acc) ,form) ,tree)) + +(defun -tree-map-nodes (pred fun tree) + "Call FUN on each node of TREE that satisfies PRED. + +If PRED returns nil, continue descending down this node. If PRED +returns non-nil, apply FUN to this node and do not descend +further." + (if (funcall pred tree) + (funcall fun tree) + (if (and (listp tree) + (not (-cons-pair? tree))) + (-map (lambda (x) (-tree-map-nodes pred fun x)) tree) + tree))) + +(defmacro --tree-map-nodes (pred form tree) + "Anaphoric form of `-tree-map-nodes'." + `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree)) + +(defun -tree-seq (branch children tree) + "Return a sequence of the nodes in TREE, in depth-first search order. + +BRANCH is a predicate of one argument that returns non-nil if the +passed argument is a branch, that is, a node that can have children. + +CHILDREN is a function of one argument that returns the children +of the passed branch node. + +Non-branch nodes are simply copied." + (cons tree + (when (funcall branch tree) + (-mapcat (lambda (x) (-tree-seq branch children x)) + (funcall children tree))))) + +(defmacro --tree-seq (branch children tree) + "Anaphoric form of `-tree-seq'." + `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree)) + +(defun -clone (list) + "Create a deep copy of LIST. +The new list has the same elements and structure but all cons are +replaced with new ones. This is useful when you need to clone a +structure such as plist or alist." + (declare (pure t) (side-effect-free t)) + (-tree-map 'identity list)) + +(defun dash-enable-font-lock () + "Add syntax highlighting to dash functions, macros and magic values." + (eval-after-load 'lisp-mode + '(progn + (let ((new-keywords '( + "!cons" + "!cdr" + "-each" + "--each" + "-each-indexed" + "--each-indexed" + "-each-while" + "--each-while" + "-doto" + "-dotimes" + "--dotimes" + "-map" + "--map" + "-reduce-from" + "--reduce-from" + "-reduce" + "--reduce" + "-reduce-r-from" + "--reduce-r-from" + "-reduce-r" + "--reduce-r" + "-reductions-from" + "-reductions-r-from" + "-reductions" + "-reductions-r" + "-filter" + "--filter" + "-select" + "--select" + "-remove" + "--remove" + "-reject" + "--reject" + "-remove-first" + "--remove-first" + "-reject-first" + "--reject-first" + "-remove-last" + "--remove-last" + "-reject-last" + "--reject-last" + "-remove-item" + "-non-nil" + "-keep" + "--keep" + "-map-indexed" + "--map-indexed" + "-splice" + "--splice" + "-splice-list" + "--splice-list" + "-map-when" + "--map-when" + "-replace-where" + "--replace-where" + "-map-first" + "--map-first" + "-map-last" + "--map-last" + "-replace" + "-replace-first" + "-replace-last" + "-flatten" + "-flatten-n" + "-concat" + "-mapcat" + "--mapcat" + "-copy" + "-cons*" + "-snoc" + "-first" + "--first" + "-find" + "--find" + "-some" + "--some" + "-any" + "--any" + "-last" + "--last" + "-first-item" + "-second-item" + "-third-item" + "-fourth-item" + "-fifth-item" + "-last-item" + "-butlast" + "-count" + "--count" + "-any?" + "--any?" + "-some?" + "--some?" + "-any-p" + "--any-p" + "-some-p" + "--some-p" + "-some->" + "-some->>" + "-some-->" + "-all?" + "-all-p" + "--all?" + "--all-p" + "-every?" + "--every?" + "-all-p" + "--all-p" + "-every-p" + "--every-p" + "-none?" + "--none?" + "-none-p" + "--none-p" + "-only-some?" + "--only-some?" + "-only-some-p" + "--only-some-p" + "-slice" + "-take" + "-drop" + "-drop-last" + "-take-last" + "-take-while" + "--take-while" + "-drop-while" + "--drop-while" + "-split-at" + "-rotate" + "-insert-at" + "-replace-at" + "-update-at" + "--update-at" + "-remove-at" + "-remove-at-indices" + "-split-with" + "--split-with" + "-split-on" + "-split-when" + "--split-when" + "-separate" + "--separate" + "-partition-all-in-steps" + "-partition-in-steps" + "-partition-all" + "-partition" + "-partition-after-item" + "-partition-after-pred" + "-partition-before-item" + "-partition-before-pred" + "-partition-by" + "--partition-by" + "-partition-by-header" + "--partition-by-header" + "-group-by" + "--group-by" + "-interpose" + "-interleave" + "-unzip" + "-zip-with" + "--zip-with" + "-zip" + "-zip-fill" + "-zip-pair" + "-cycle" + "-pad" + "-annotate" + "--annotate" + "-table" + "-table-flat" + "-partial" + "-elem-index" + "-elem-indices" + "-find-indices" + "--find-indices" + "-find-index" + "--find-index" + "-find-last-index" + "--find-last-index" + "-select-by-indices" + "-select-columns" + "-select-column" + "-grade-up" + "-grade-down" + "->" + "->>" + "-->" + "-as->" + "-when-let" + "-when-let*" + "--when-let" + "-if-let" + "-if-let*" + "--if-let" + "-let*" + "-let" + "-lambda" + "-distinct" + "-uniq" + "-union" + "-intersection" + "-difference" + "-powerset" + "-permutations" + "-inits" + "-tails" + "-common-prefix" + "-common-suffix" + "-contains?" + "-contains-p" + "-same-items?" + "-same-items-p" + "-is-prefix-p" + "-is-prefix?" + "-is-suffix-p" + "-is-suffix?" + "-is-infix-p" + "-is-infix?" + "-sort" + "--sort" + "-list" + "-repeat" + "-sum" + "-running-sum" + "-product" + "-running-product" + "-max" + "-min" + "-max-by" + "--max-by" + "-min-by" + "--min-by" + "-iterate" + "--iterate" + "-fix" + "--fix" + "-unfold" + "--unfold" + "-cons-pair?" + "-cons-pair-p" + "-cons-to-list" + "-value-to-list" + "-tree-mapreduce-from" + "--tree-mapreduce-from" + "-tree-mapreduce" + "--tree-mapreduce" + "-tree-map" + "--tree-map" + "-tree-reduce-from" + "--tree-reduce-from" + "-tree-reduce" + "--tree-reduce" + "-tree-seq" + "--tree-seq" + "-tree-map-nodes" + "--tree-map-nodes" + "-clone" + "-rpartial" + "-juxt" + "-applify" + "-on" + "-flip" + "-const" + "-cut" + "-orfn" + "-andfn" + "-iteratefn" + "-fixfn" + "-prodfn" + )) + (special-variables '( + "it" + "it-index" + "acc" + "other" + ))) + (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>") + 1 font-lock-variable-name-face)) 'append) + (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>") + 1 font-lock-keyword-face)) 'append)) + (--each (buffer-list) + (with-current-buffer it + (when (and (eq major-mode 'emacs-lisp-mode) + (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-refresh-defaults))))))) + +(provide 'dash) +;;; dash.el ends here diff --git a/elpa/dash-20191024.1908/dash.elc b/elpa/dash-20191024.1908/dash.elc new file mode 100644 index 0000000000000000000000000000000000000000..8a69f39d0c8d70b833758ef9487b98c6a95c0155 GIT binary patch literal 101188 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")) :maintainer '("SAKURAI Masashi ") :url "https://github.com/kiwanami/emacs-deferred") diff --git a/elpa/deferred-20170901.1330/deferred.el b/elpa/deferred-20170901.1330/deferred.el new file mode 100644 index 0000000..af87445 --- /dev/null +++ b/elpa/deferred-20170901.1330/deferred.el @@ -0,0 +1,972 @@ +;;; deferred.el --- Simple asynchronous functions for emacs lisp -*- lexical-binding: t; -*- + +;; Copyright (C) 2010-2016 SAKURAI Masashi + +;; Author: SAKURAI Masashi +;; Version: 0.5.1 +;; Package-Version: 20170901.1330 +;; Keywords: deferred, async +;; Package-Requires: ((emacs "24.4")) +;; URL: https://github.com/kiwanami/emacs-deferred + +;; 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: + +;; 'deferred.el' is a simple library for asynchronous tasks. +;; [https://github.com/kiwanami/emacs-deferred] + +;; The API is almost the same as JSDeferred written by cho45. See the +;; JSDeferred and Mochikit.Async web sites for further documentations. +;; [https://github.com/cho45/jsdeferred] +;; [http://mochikit.com/doc/html/MochiKit/Async.html] + +;; A good introduction document (JavaScript) +;; [http://cho45.stfuawsc.com/jsdeferred/doc/intro.en.html] + +;;; Samples: + +;; ** HTTP Access + +;; (require 'url) +;; (deferred:$ +;; (deferred:url-retrieve "http://www.gnu.org") +;; (deferred:nextc it +;; (lambda (buf) +;; (insert (with-current-buffer buf (buffer-string))) +;; (kill-buffer buf)))) + +;; ** Invoking command tasks + +;; (deferred:$ +;; (deferred:process "wget" "-O" "a.jpg" "http://www.gnu.org/software/emacs/tour/images/splash.png") +;; (deferred:nextc it +;; (lambda (x) (deferred:process "convert" "a.jpg" "-resize" "100x100" "jpg:b.jpg"))) +;; (deferred:nextc it +;; (lambda (x) +;; (insert-image (create-image (expand-file-name "b.jpg") 'jpeg nil))))) + +;; See the readme for further API documentation. + +;; ** Applications + +;; *Inertial scrolling for Emacs +;; [https://github.com/kiwanami/emacs-inertial-scroll] + +;; This program makes simple multi-thread function, using +;; deferred.el. + +(require 'cl-lib) +(require 'subr-x) + +(declare-function pp-display-expression 'pp) + +(defvar deferred:version nil "deferred.el version") +(setq deferred:version "0.5.0") + +;;; Code: + +(defmacro deferred:aand (test &rest rest) + "[internal] Anaphoric AND." + (declare (debug ("test" form &rest form))) + `(let ((it ,test)) + (if it ,(if rest `(deferred:aand ,@rest) 'it)))) + +(defmacro deferred:$ (&rest elements) + "Anaphoric function chain macro for deferred chains." + (declare (debug (&rest form))) + `(let (it) + ,@(cl-loop for i in elements + collect + `(setq it ,i)) + it)) + +(defmacro deferred:lambda (args &rest body) + "Anaphoric lambda macro for self recursion." + (declare (debug ("args" form &rest form))) + (let ((argsyms (cl-loop repeat (length args) collect (cl-gensym)))) + `(lambda (,@argsyms) + (let (self) + (setq self (lambda( ,@args ) ,@body)) + (funcall self ,@argsyms))))) + +(cl-defmacro deferred:try (d &key catch finally) + "Try-catch-finally macro. This macro simulates the +try-catch-finally block asynchronously. CATCH and FINALLY can be +nil. Because of asynchrony, this macro does not ensure that the +task FINALLY should be called." + (let ((chain + (if catch `((deferred:error it ,catch))))) + (when finally + (setq chain (append chain `((deferred:watch it ,finally))))) + `(deferred:$ ,d ,@chain))) + +(defun deferred:setTimeout (f msec) + "[internal] Timer function that emulates the `setTimeout' function in JS." + (run-at-time (/ msec 1000.0) nil f)) + +(defun deferred:cancelTimeout (id) + "[internal] Timer cancellation function that emulates the `cancelTimeout' function in JS." + (cancel-timer id)) + +(defun deferred:run-with-idle-timer (sec f) + "[internal] Wrapper function for run-with-idle-timer." + (run-with-idle-timer sec nil f)) + +(defun deferred:call-lambda (f &optional arg) + "[internal] Call a function with one or zero argument safely. +The lambda function can define with zero and one argument." + (condition-case err + (funcall f arg) + ('wrong-number-of-arguments + (display-warning 'deferred "\ +Callback that takes no argument may be specified. +Passing callback with no argument is deprecated. +Callback must take one argument. +Or, this error is coming from somewhere inside of the callback: %S" err) + (condition-case nil + (funcall f) + ('wrong-number-of-arguments + (signal 'wrong-number-of-arguments (cdr err))))))) ; return the first error + +;; debug + +(eval-and-compile + (defvar deferred:debug nil "Debug output switch.")) +(defvar deferred:debug-count 0 "[internal] Debug output counter.") + +(defmacro deferred:message (&rest args) + "[internal] Debug log function." + (when deferred:debug + `(progn + (with-current-buffer (get-buffer-create "*deferred:debug*") + (save-excursion + (goto-char (point-max)) + (insert (format "%5i %s\n" deferred:debug-count (format ,@args))))) + (cl-incf deferred:debug-count)))) + +(defun deferred:message-mark () + "[internal] Debug log function." + (interactive) + (deferred:message "==================== mark ==== %s" + (format-time-string "%H:%M:%S" (current-time)))) + +(defun deferred:pp (d) + (require 'pp) + (deferred:$ + (deferred:nextc d + (lambda (x) + (pp-display-expression x "*deferred:pp*"))) + (deferred:error it + (lambda (e) + (pp-display-expression e "*deferred:pp*"))) + (deferred:nextc it + (lambda (_x) (pop-to-buffer "*deferred:pp*"))))) + +(defvar deferred:debug-on-signal nil +"If non nil, the value `debug-on-signal' is substituted this +value in the `condition-case' form in deferred +implementations. Then, Emacs debugger can catch an error occurred +in the asynchronous tasks.") + +(defmacro deferred:condition-case (var protected-form &rest handlers) + "[internal] Custom condition-case. See the comment for +`deferred:debug-on-signal'." + (declare (debug condition-case) + (indent 2)) + `(let ((debug-on-signal + (or debug-on-signal deferred:debug-on-signal))) + (condition-case ,var + ,protected-form + ,@handlers))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Back end functions of deferred tasks + +(defvar deferred:tick-time 0.001 + "Waiting time between asynchronous tasks (second). +The shorter waiting time increases the load of Emacs. The end +user can tune this parameter. However, applications should not +modify it because the applications run on various environments.") + +(defvar deferred:queue nil + "[internal] The execution queue of deferred objects. +See the functions `deferred:post-task' and `deferred:worker'.") + +(defmacro deferred:pack (a b c) + `(cons ,a (cons ,b ,c))) + +(defun deferred:schedule-worker () + "[internal] Schedule consuming a deferred task in the execution queue." + (run-at-time deferred:tick-time nil 'deferred:worker)) + +(defun deferred:post-task (d which &optional arg) + "[internal] Add a deferred object to the execution queue +`deferred:queue' and schedule to execute. +D is a deferred object. WHICH is a symbol, `ok' or `ng'. ARG is +an argument value for execution of the deferred task." + (push (deferred:pack d which arg) deferred:queue) + (deferred:message "QUEUE-POST [%s]: %s" + (length deferred:queue) (deferred:pack d which arg)) + (deferred:schedule-worker) + d) + +(defun deferred:clear-queue () + "Clear the execution queue. For test and debugging." + (interactive) + (deferred:message "QUEUE-CLEAR [%s -> 0]" (length deferred:queue)) + (setq deferred:queue nil)) + +(defun deferred:worker () + "[internal] Consume a deferred task. +Mainly this function is called by timer asynchronously." + (when deferred:queue + (let* ((pack (car (last deferred:queue))) + (d (car pack)) + (which (cadr pack)) + (arg (cddr pack)) value) + (setq deferred:queue (nbutlast deferred:queue)) + (condition-case err + (setq value (deferred:exec-task d which arg)) + (error + (deferred:message "ERROR : %s" err) + (message "deferred error : %s" err))) + value))) + +(defun deferred:flush-queue! () + "Call all deferred tasks synchronously. For test and debugging." + (let (value) + (while deferred:queue + (setq value (deferred:worker))) + value)) + +(defun deferred:sync! (d) + "Wait for the given deferred task. For test and debugging. +Error is raised if it is not processed within deferred chain D." + (progn + (let ((last-value 'deferred:undefined*) + uncaught-error) + (deferred:try + (deferred:nextc d + (lambda (x) (setq last-value x))) + :catch + (lambda (err) (setq uncaught-error err))) + (while (and (eq 'deferred:undefined* last-value) + (not uncaught-error)) + (sit-for 0.05) + (sleep-for 0.05)) + (when uncaught-error + (deferred:resignal uncaught-error)) + last-value))) + + + +;; Struct: deferred +;; +;; callback : a callback function (default `deferred:default-callback') +;; errorback : an errorback function (default `deferred:default-errorback') +;; cancel : a canceling function (default `deferred:default-cancel') +;; next : a next chained deferred object (default nil) +;; status : if 'ok or 'ng, this deferred has a result (error) value. (default nil) +;; value : saved value (default nil) +;; +(cl-defstruct deferred + (callback 'deferred:default-callback) + (errorback 'deferred:default-errorback) + (cancel 'deferred:default-cancel) + next status value) + +(defun deferred:default-callback (i) + "[internal] Default callback function." + (identity i)) + +(defun deferred:default-errorback (err) + "[internal] Default errorback function." + (deferred:resignal err)) + +(defun deferred:resignal (err) + "[internal] Safely resignal ERR as an Emacs condition. + +If ERR is a cons (ERROR-SYMBOL . DATA) where ERROR-SYMBOL has an +`error-conditions' property, it is re-signaled unchanged. If ERR +is a string, it is signaled as a generic error using `error'. +Otherwise, ERR is formatted into a string as if by `print' before +raising with `error'." + (cond ((and (listp err) + (symbolp (car err)) + (get (car err) 'error-conditions)) + (signal (car err) (cdr err))) + ((stringp err) + (error "%s" err)) + (t + (error "%S" err)))) + +(defun deferred:default-cancel (d) + "[internal] Default canceling function." + (deferred:message "CANCEL : %s" d) + (setf (deferred-callback d) 'deferred:default-callback) + (setf (deferred-errorback d) 'deferred:default-errorback) + (setf (deferred-next d) nil) + d) + +(defvar deferred:onerror nil + "Default error handler. This value is nil or a function that + have one argument for the error message.") + +(defun deferred:exec-task (d which &optional arg) + "[internal] Executing deferred task. If the deferred object has +next deferred task or the return value is a deferred object, this +function adds the task to the execution queue. +D is a deferred object. WHICH is a symbol, `ok' or `ng'. ARG is +an argument value for execution of the deferred task." + (deferred:message "EXEC : %s / %s / %s" d which arg) + (when (null d) (error "deferred:exec-task was given a nil.")) + (let ((callback (if (eq which 'ok) + (deferred-callback d) + (deferred-errorback d))) + (next-deferred (deferred-next d))) + (cond + (callback + (deferred:condition-case err + (let ((value (deferred:call-lambda callback arg))) + (cond + ((deferred-p value) + (deferred:message "WAIT NEST : %s" value) + (if next-deferred + (deferred:set-next value next-deferred) + value)) + (t + (if next-deferred + (deferred:post-task next-deferred 'ok value) + (setf (deferred-status d) 'ok) + (setf (deferred-value d) value) + value)))) + (error + (cond + (next-deferred + (deferred:post-task next-deferred 'ng err)) + (deferred:onerror + (deferred:call-lambda deferred:onerror err)) + (t + (deferred:message "ERROR : %S" err) + (message "deferred error : %S" err) + (setf (deferred-status d) 'ng) + (setf (deferred-value d) err) + err))))) + (t ; <= (null callback) + (cond + (next-deferred + (deferred:exec-task next-deferred which arg)) + ((eq which 'ok) arg) + (t ; (eq which 'ng) + (deferred:resignal arg))))))) + +(defun deferred:set-next (prev next) + "[internal] Connect deferred objects." + (setf (deferred-next prev) next) + (cond + ((eq 'ok (deferred-status prev)) + (setf (deferred-status prev) nil) + (let ((ret (deferred:exec-task + next 'ok (deferred-value prev)))) + (if (deferred-p ret) ret + next))) + ((eq 'ng (deferred-status prev)) + (setf (deferred-status prev) nil) + (let ((ret (deferred:exec-task next 'ng (deferred-value prev)))) + (if (deferred-p ret) ret + next))) + (t + next))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Basic functions for deferred objects + +(defun deferred:new (&optional callback) + "Create a deferred object." + (if callback + (make-deferred :callback callback) + (make-deferred))) + +(defun deferred:callback (d &optional arg) + "Start deferred chain with a callback message." + (deferred:exec-task d 'ok arg)) + +(defun deferred:errorback (d &optional arg) + "Start deferred chain with an errorback message." + (deferred:exec-task d 'ng arg)) + +(defun deferred:callback-post (d &optional arg) + "Add the deferred object to the execution queue." + (deferred:post-task d 'ok arg)) + +(defun deferred:errorback-post (d &optional arg) + "Add the deferred object to the execution queue." + (deferred:post-task d 'ng arg)) + +(defun deferred:cancel (d) + "Cancel all callbacks and deferred chain in the deferred object." + (deferred:message "CANCEL : %s" d) + (funcall (deferred-cancel d) d) + d) + +(defun deferred:status (d) + "Return a current status of the deferred object. The returned value means following: +`ok': the callback was called and waiting for next deferred. +`ng': the errorback was called and waiting for next deferred. + nil: The neither callback nor errorback was not called." + (deferred-status d)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Basic utility functions + +(defun deferred:succeed (&optional arg) + "Create a synchronous deferred object." + (let ((d (deferred:new))) + (deferred:exec-task d 'ok arg) + d)) + +(defun deferred:fail (&optional arg) + "Create a synchronous deferred object." + (let ((d (deferred:new))) + (deferred:exec-task d 'ng arg) + d)) + +(defun deferred:next (&optional callback arg) + "Create a deferred object and schedule executing. This function +is a short cut of following code: + (deferred:callback-post (deferred:new callback))." + (let ((d (if callback + (make-deferred :callback callback) + (make-deferred)))) + (deferred:callback-post d arg) + d)) + +(defun deferred:nextc (d callback) + "Create a deferred object with OK callback and connect it to the given deferred object." + (let ((nd (make-deferred :callback callback))) + (deferred:set-next d nd))) + +(defun deferred:error (d callback) + "Create a deferred object with errorback and connect it to the given deferred object." + (let ((nd (make-deferred :errorback callback))) + (deferred:set-next d nd))) + +(defun deferred:watch (d callback) + "Create a deferred object with watch task and connect it to the given deferred object. +The watch task CALLBACK can not affect deferred chains with +return values. This function is used in following purposes, +simulation of try-finally block in asynchronous tasks, progress +monitoring of tasks." + (let* ((callback callback) + (normal (lambda (x) (ignore-errors (deferred:call-lambda callback x)) x)) + (err (lambda (e) + (ignore-errors (deferred:call-lambda callback e)) + (deferred:resignal e)))) + (let ((nd (make-deferred :callback normal :errorback err))) + (deferred:set-next d nd)))) + +(defun deferred:wait (msec) + "Return a deferred object scheduled at MSEC millisecond later." + (let ((d (deferred:new)) (start-time (float-time)) timer) + (deferred:message "WAIT : %s" msec) + (setq timer (deferred:setTimeout + (lambda () + (deferred:exec-task d 'ok + (* 1000.0 (- (float-time) start-time))) + nil) msec)) + (setf (deferred-cancel d) + (lambda (x) + (deferred:cancelTimeout timer) + (deferred:default-cancel x))) + d)) + +(defun deferred:wait-idle (msec) + "Return a deferred object which will run when Emacs has been +idle for MSEC millisecond." + (let ((d (deferred:new)) (start-time (float-time)) timer) + (deferred:message "WAIT-IDLE : %s" msec) + (setq timer + (deferred:run-with-idle-timer + (/ msec 1000.0) + (lambda () + (deferred:exec-task d 'ok + (* 1000.0 (- (float-time) start-time))) + nil))) + (setf (deferred-cancel d) + (lambda (x) + (deferred:cancelTimeout timer) + (deferred:default-cancel x))) + d)) + +(defun deferred:call (f &rest args) + "Call the given function asynchronously." + (deferred:next + (lambda (_x) + (apply f args)))) + +(defun deferred:apply (f &optional args) + "Call the given function asynchronously." + (deferred:next + (lambda (_x) + (apply f args)))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Utility functions + +(defun deferred:empty-p (times-or-seq) + "[internal] Return non-nil if TIMES-OR-SEQ is the number zero or nil." + (or (and (numberp times-or-seq) (<= times-or-seq 0)) + (and (sequencep times-or-seq) (= (length times-or-seq) 0)))) + +(defun deferred:loop (times-or-seq func) + "Return a iteration deferred object." + (deferred:message "LOOP : %s" times-or-seq) + (if (deferred:empty-p times-or-seq) (deferred:next) + (let* (items (rd + (cond + ((numberp times-or-seq) + (cl-loop for i from 0 below times-or-seq + with ld = (deferred:next) + do + (push ld items) + (setq ld + (let ((i i)) + (deferred:nextc ld + (lambda (_x) (deferred:call-lambda func i))))) + finally return ld)) + ((sequencep times-or-seq) + (cl-loop for i in (append times-or-seq nil) ; seq->list + with ld = (deferred:next) + do + (push ld items) + (setq ld + (let ((i i)) + (deferred:nextc ld + (lambda (_x) (deferred:call-lambda func i))))) + finally return ld))))) + (setf (deferred-cancel rd) + (lambda (x) (deferred:default-cancel x) + (cl-loop for i in items + do (deferred:cancel i)))) + rd))) + +(defun deferred:trans-multi-args (args self-func list-func main-func) + "[internal] Check the argument values and dispatch to methods." + (cond + ((and (= 1 (length args)) (consp (car args)) (not (functionp (car args)))) + (let ((lst (car args))) + (cond + ((or (null lst) (null (car lst))) + (deferred:next)) + ((deferred:aand lst (car it) (or (functionp it) (deferred-p it))) + ;; a list of deferred objects + (funcall list-func lst)) + ((deferred:aand lst (consp it)) + ;; an alist of deferred objects + (funcall main-func lst)) + (t (error "Wrong argument type. %s" args))))) + (t (funcall self-func args)))) + +(defun deferred:parallel-array-to-alist (lst) + "[internal] Translation array to alist." + (cl-loop for d in lst + for i from 0 below (length lst) + collect (cons i d))) + +(defun deferred:parallel-alist-to-array (alst) + "[internal] Translation alist to array." + (cl-loop for pair in + (sort alst (lambda (x y) + (< (car x) (car y)))) + collect (cdr pair))) + +(defun deferred:parallel-func-to-deferred (alst) + "[internal] Normalization for parallel and earlier arguments." + (cl-loop for pair in alst + for d = (cdr pair) + collect + (progn + (unless (deferred-p d) + (setf (cdr pair) (deferred:next d))) + pair))) + +(defun deferred:parallel-main (alst) + "[internal] Deferred alist implementation for `deferred:parallel'. " + (deferred:message "PARALLEL" ) + (let ((nd (deferred:new)) + (len (length alst)) + values) + (cl-loop for pair in + (deferred:parallel-func-to-deferred alst) + with cd ; current child deferred + do + (let ((name (car pair))) + (setq cd + (deferred:nextc (cdr pair) + (lambda (x) + (push (cons name x) values) + (deferred:message "PARALLEL VALUE [%s/%s] %s" + (length values) len (cons name x)) + (when (= len (length values)) + (deferred:message "PARALLEL COLLECTED") + (deferred:post-task nd 'ok (nreverse values))) + nil))) + (deferred:error cd + (lambda (e) + (push (cons name e) values) + (deferred:message "PARALLEL ERROR [%s/%s] %s" + (length values) len (cons name e)) + (when (= (length values) len) + (deferred:message "PARALLEL COLLECTED") + (deferred:post-task nd 'ok (nreverse values))) + nil)))) + nd)) + +(defun deferred:parallel-list (lst) + "[internal] Deferred list implementation for `deferred:parallel'. " + (deferred:message "PARALLEL" ) + (let* ((pd (deferred:parallel-main (deferred:parallel-array-to-alist lst))) + (rd (deferred:nextc pd 'deferred:parallel-alist-to-array))) + (setf (deferred-cancel rd) + (lambda (x) (deferred:default-cancel x) + (deferred:cancel pd))) + rd)) + +(defun deferred:parallel (&rest args) + "Return a deferred object that calls given deferred objects or +functions in parallel and wait for all callbacks. The following +deferred task will be called with an array of the return +values. ARGS can be a list or an alist of deferred objects or +functions." + (deferred:message "PARALLEL : %s" args) + (deferred:trans-multi-args args + 'deferred:parallel 'deferred:parallel-list 'deferred:parallel-main)) + +(defun deferred:earlier-main (alst) + "[internal] Deferred alist implementation for `deferred:earlier'. " + (deferred:message "EARLIER" ) + (let ((nd (deferred:new)) + (len (length alst)) + value results) + (cl-loop for pair in + (deferred:parallel-func-to-deferred alst) + with cd ; current child deferred + do + (let ((name (car pair))) + (setq cd + (deferred:nextc (cdr pair) + (lambda (x) + (push (cons name x) results) + (cond + ((null value) + (setq value (cons name x)) + (deferred:message "EARLIER VALUE %s" (cons name value)) + (deferred:post-task nd 'ok value)) + (t + (deferred:message "EARLIER MISS [%s/%s] %s" (length results) len (cons name value)) + (when (eql (length results) len) + (deferred:message "EARLIER COLLECTED")))) + nil))) + (deferred:error cd + (lambda (e) + (push (cons name e) results) + (deferred:message "EARLIER ERROR [%s/%s] %s" (length results) len (cons name e)) + (when (and (eql (length results) len) (null value)) + (deferred:message "EARLIER FAILED") + (deferred:post-task nd 'ok nil)) + nil)))) + nd)) + +(defun deferred:earlier-list (lst) + "[internal] Deferred list implementation for `deferred:earlier'. " + (deferred:message "EARLIER" ) + (let* ((pd (deferred:earlier-main (deferred:parallel-array-to-alist lst))) + (rd (deferred:nextc pd (lambda (x) (cdr x))))) + (setf (deferred-cancel rd) + (lambda (x) (deferred:default-cancel x) + (deferred:cancel pd))) + rd)) + + +(defun deferred:earlier (&rest args) + "Return a deferred object that calls given deferred objects or +functions in parallel and wait for the first callback. The +following deferred task will be called with the first return +value. ARGS can be a list or an alist of deferred objects or +functions." + (deferred:message "EARLIER : %s" args) + (deferred:trans-multi-args args + 'deferred:earlier 'deferred:earlier-list 'deferred:earlier-main)) + +(defmacro deferred:timeout (timeout-msec timeout-form d) + "Time out macro on a deferred task D. If the deferred task D +does not complete within TIMEOUT-MSEC, this macro cancels the +deferred task and return the TIMEOUT-FORM." + `(deferred:earlier + (deferred:nextc (deferred:wait ,timeout-msec) + (lambda (x) ,timeout-form)) + ,d)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Application functions + +(defvar deferred:uid 0 "[internal] Sequence number for some utilities. See the function `deferred:uid'.") + +(defun deferred:uid () + "[internal] Generate a sequence number." + (cl-incf deferred:uid)) + +(defun deferred:buffer-string (strformat buf) + "[internal] Return a string in the buffer with the given format." + (format strformat + (with-current-buffer buf (buffer-string)))) + +(defun deferred:process (command &rest args) + "A deferred wrapper of `start-process'. Return a deferred +object. The process name and buffer name of the argument of the +`start-process' are generated by this function automatically. +The next deferred object receives stdout and stderr string from +the command process." + (deferred:process-gen 'start-process command args)) + +(defun deferred:process-shell (command &rest args) + "A deferred wrapper of `start-process-shell-command'. Return a deferred +object. The process name and buffer name of the argument of the +`start-process-shell-command' are generated by this function automatically. +The next deferred object receives stdout and stderr string from +the command process." + (deferred:process-gen 'start-process-shell-command command args)) + +(defun deferred:process-buffer (command &rest args) + "A deferred wrapper of `start-process'. Return a deferred +object. The process name and buffer name of the argument of the +`start-process' are generated by this function automatically. +The next deferred object receives stdout and stderr buffer from +the command process." + (deferred:process-buffer-gen 'start-process command args)) + +(defun deferred:process-shell-buffer (command &rest args) + "A deferred wrapper of `start-process-shell-command'. Return a deferred +object. The process name and buffer name of the argument of the +`start-process-shell-command' are generated by this function automatically. +The next deferred object receives stdout and stderr buffer from +the command process." + (deferred:process-buffer-gen 'start-process-shell-command command args)) + +(defun deferred:process-gen (f command args) + "[internal]" + (let ((pd (deferred:process-buffer-gen f command args)) d) + (setq d (deferred:nextc pd + (lambda (buf) + (prog1 + (with-current-buffer buf (buffer-string)) + (kill-buffer buf))))) + (setf (deferred-cancel d) + (lambda (_x) + (deferred:default-cancel d) + (deferred:default-cancel pd))) + d)) + +(defun deferred:process-buffer-gen (f command args) + "[internal]" + (let ((d (deferred:next)) (uid (deferred:uid))) + (let ((proc-name (format "*deferred:*%s*:%s" command uid)) + (buf-name (format " *deferred:*%s*:%s" command uid)) + (pwd default-directory) + (env process-environment) + (con-type process-connection-type) + (nd (deferred:new)) proc-buf proc) + (deferred:nextc d + (lambda (_x) + (setq proc-buf (get-buffer-create buf-name)) + (condition-case err + (let ((default-directory pwd) + (process-environment env) + (process-connection-type con-type)) + (setq proc + (if (null (car args)) + (apply f proc-name buf-name command nil) + (apply f proc-name buf-name command args))) + (set-process-sentinel + proc + (lambda (proc event) + (unless (process-live-p proc) + (if (zerop (process-exit-status proc)) + (deferred:post-task nd 'ok proc-buf) + (let ((msg (format "Deferred process exited abnormally:\n command: %s\n exit status: %s %s\n event: %s\n buffer contents: %S" + command + (process-status proc) + (process-exit-status proc) + (string-trim-right event) + (if (buffer-live-p proc-buf) + (with-current-buffer proc-buf + (buffer-string)) + "(unavailable)")))) + (kill-buffer proc-buf) + (deferred:post-task nd 'ng msg)))))) + (setf (deferred-cancel nd) + (lambda (x) (deferred:default-cancel x) + (when proc + (kill-process proc) + (kill-buffer proc-buf))))) + (error (deferred:post-task nd 'ng err))) + nil)) + nd))) + +(defmacro deferred:processc (d command &rest args) + "Process chain of `deferred:process'." + `(deferred:nextc ,d + (lambda (,(cl-gensym)) (deferred:process ,command ,@args)))) + +(defmacro deferred:process-bufferc (d command &rest args) + "Process chain of `deferred:process-buffer'." + `(deferred:nextc ,d + (lambda (,(cl-gensym)) (deferred:process-buffer ,command ,@args)))) + +(defmacro deferred:process-shellc (d command &rest args) + "Process chain of `deferred:process'." + `(deferred:nextc ,d + (lambda (,(cl-gensym)) (deferred:process-shell ,command ,@args)))) + +(defmacro deferred:process-shell-bufferc (d command &rest args) + "Process chain of `deferred:process-buffer'." + `(deferred:nextc ,d + (lambda (,(cl-gensym)) (deferred:process-shell-buffer ,command ,@args)))) + +;; Special variables defined in url-vars.el. +(defvar url-request-data) +(defvar url-request-method) +(defvar url-request-extra-headers) + +(declare-function url-http-symbol-value-in-buffer "url-http" + (symbol buffer &optional unbound-value)) + +(declare-function deferred:url-param-serialize "request" (params)) + +(declare-function deferred:url-escape "request" (val)) + +(eval-after-load "url" + ;; for url package + ;; TODO: proxy, charaset + ;; List of gloabl variables to preserve and restore before url-retrieve call + '(let ((url-global-variables '(url-request-data + url-request-method + url-request-extra-headers))) + + (defun deferred:url-retrieve (url &optional cbargs silent inhibit-cookies) + "A wrapper function for url-retrieve. The next deferred +object receives the buffer object that URL will load +into. Values of dynamically bound 'url-request-data', 'url-request-method' and +'url-request-extra-headers' are passed to url-retrieve call." + (let ((nd (deferred:new)) + buf + (local-values (mapcar (lambda (symbol) (symbol-value symbol)) url-global-variables))) + (deferred:next + (lambda (_x) + (cl-progv url-global-variables local-values + (condition-case err + (setq buf + (url-retrieve + url (lambda (_xx) (deferred:post-task nd 'ok buf)) + cbargs silent inhibit-cookies)) + (error (deferred:post-task nd 'ng err))) + nil))) + (setf (deferred-cancel nd) + (lambda (_x) + (when (buffer-live-p buf) + (kill-buffer buf)))) + nd)) + + (defun deferred:url-delete-header (buf) + (with-current-buffer buf + (let ((pos (url-http-symbol-value-in-buffer + 'url-http-end-of-headers buf))) + (when pos + (delete-region (point-min) (1+ pos))))) + buf) + + (defun deferred:url-delete-buffer (buf) + (when (and buf (buffer-live-p buf)) + (kill-buffer buf)) + nil) + + (defun deferred:url-get (url &optional params &rest args) + "Perform a HTTP GET method with `url-retrieve'. PARAMS is +a parameter list of (key . value) or key. ARGS will be appended +to deferred:url-retrieve args list. The next deferred +object receives the buffer object that URL will load into." + (when params + (setq url + (concat url "?" (deferred:url-param-serialize params)))) + (let ((d (deferred:$ + (apply 'deferred:url-retrieve url args) + (deferred:nextc it 'deferred:url-delete-header)))) + (deferred:set-next + d (deferred:new 'deferred:url-delete-buffer)) + d)) + + (defun deferred:url-post (url &optional params &rest args) + "Perform a HTTP POST method with `url-retrieve'. PARAMS is +a parameter list of (key . value) or key. ARGS will be appended +to deferred:url-retrieve args list. The next deferred +object receives the buffer object that URL will load into." + (let ((url-request-method "POST") + (url-request-extra-headers + (append url-request-extra-headers + '(("Content-Type" . "application/x-www-form-urlencoded")))) + (url-request-data (deferred:url-param-serialize params))) + (let ((d (deferred:$ + (apply 'deferred:url-retrieve url args) + (deferred:nextc it 'deferred:url-delete-header)))) + (deferred:set-next + d (deferred:new 'deferred:url-delete-buffer)) + d))) + + (defun deferred:url-escape (val) + "[internal] Return a new string that is VAL URI-encoded." + (unless (stringp val) + (setq val (format "%s" val))) + (url-hexify-string + (encode-coding-string val 'utf-8))) + + (defun deferred:url-param-serialize (params) + "[internal] Serialize a list of (key . value) cons cells +into a query string." + (when params + (mapconcat + 'identity + (cl-loop for p in params + collect + (cond + ((consp p) + (concat + (deferred:url-escape (car p)) "=" + (deferred:url-escape (cdr p)))) + (t + (deferred:url-escape p)))) + "&"))) + )) + + +(provide 'deferred) +;;; deferred.el ends here diff --git a/elpa/deferred-20170901.1330/deferred.elc b/elpa/deferred-20170901.1330/deferred.elc new file mode 100644 index 0000000000000000000000000000000000000000..05b40cd735ffec2fc0939a5b09bbcdcdaf34465c GIT binary patch literal 39152 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 +;; Maintainer: Johan Andersson +;; Version: 0.20.0 +;; Package-Version: 20190109.906 +;; Keywords: files, directories +;; URL: http://github.com/rejeep/f.el +;; Package-Requires: ((s "1.7.0") (dash "2.2.0")) + +;; This file is NOT part of GNU Emacs. + +;;; License: + +;; 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, 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Code: + + + +(require 's) +(require 'dash) + +(put 'f-guard-error 'error-conditions '(error f-guard-error)) +(put 'f-guard-error 'error-message "Destructive operation outside sandbox") + +(defvar f--guard-paths nil + "List of allowed paths to modify when guarded. + +Do not modify this variable.") + +(defmacro f--destructive (path &rest body) + "If PATH is allowed to be modified, yield BODY. + +If PATH is not allowed to be modified, throw error." + (declare (indent 1)) + `(if f--guard-paths + (if (--any? (or (f-same? it ,path) + (f-ancestor-of? it ,path)) f--guard-paths) + (progn ,@body) + (signal 'f-guard-error (list ,path f--guard-paths))) + ,@body)) + + +;;;; Paths + +(defun f-join (&rest args) + "Join ARGS to a single path." + (let (path (relative (f-relative? (car args)))) + (-map + (lambda (arg) + (setq path (f-expand arg path))) + args) + (if relative (f-relative path) path))) + +(defun f-split (path) + "Split PATH and return list containing parts." + (let ((parts (s-split (f-path-separator) path 'omit-nulls))) + (if (f-absolute? path) + (push (f-path-separator) parts) + parts))) + +(defun f-expand (path &optional dir) + "Expand PATH relative to DIR (or `default-directory'). +PATH and DIR can be either a directory names or directory file +names. Return a directory name if PATH is a directory name, and +a directory file name otherwise. File name handlers are +ignored." + (let (file-name-handler-alist) + (expand-file-name path dir))) + +(defun f-filename (path) + "Return the name of PATH." + (file-name-nondirectory (directory-file-name path))) + +(defalias 'f-parent 'f-dirname) +(defun f-dirname (path) + "Return the parent directory to PATH." + (let ((parent (file-name-directory + (directory-file-name (f-expand path default-directory))))) + (unless (f-same? path parent) + (if (f-relative? path) + (f-relative parent) + (directory-file-name parent))))) + +(defun f-common-parent (paths) + "Return the deepest common parent directory of PATHS." + (cond + ((not paths) nil) + ((not (cdr paths)) (f-parent (car paths))) + (:otherwise + (let* ((paths (-map 'f-split paths)) + (common (caar paths)) + (re nil)) + (while (and (not (null (car paths))) (--all? (equal (car it) common) paths)) + (setq paths (-map 'cdr paths)) + (push common re) + (setq common (caar paths))) + (cond + ((null re) "") + ((and (= (length re) 1) (f-root? (car re))) + (f-root)) + (:otherwise + (concat (apply 'f-join (nreverse re)) "/"))))))) + +(defun f-ext (path) + "Return the file extension of PATH. + +The extension, in a file name, is the part that follows the last +'.', excluding version numbers and backup suffixes." + (file-name-extension path)) + +(defun f-no-ext (path) + "Return everything but the file extension of PATH." + (file-name-sans-extension path)) + +(defun f-swap-ext (path ext) + "Return PATH but with EXT as the new extension. +EXT must not be nil or empty." + (if (s-blank? ext) + (error "Extension cannot be empty or nil") + (concat (f-no-ext path) "." ext))) + +(defun f-base (path) + "Return the name of PATH, excluding the extension of file." + (f-no-ext (f-filename path))) + +(defun f-relative (path &optional dir) + "Return PATH relative to DIR." + (file-relative-name path dir)) + +(defalias 'f-abbrev 'f-short) +(defun f-short (path) + "Return abbrev of PATH. See `abbreviate-file-name'." + (abbreviate-file-name path)) + +(defun f-long (path) + "Return long version of PATH." + (f-expand path)) + +(defun f-canonical (path) + "Return the canonical name of PATH." + (file-truename path)) + +(defun f-slash (path) + "Append slash to PATH unless one already. + +Some functions, such as `call-process' requires there to be an +ending slash." + (if (f-dir? path) + (file-name-as-directory path) + path)) + +(defun f-full (path) + "Return absolute path to PATH, with ending slash." + (f-slash (f-long path))) + +(defun f--uniquify (paths) + "Helper for `f-uniquify' and `f-uniquify-alist'." + (let* ((files-length (length paths)) + (uniq-filenames (--map (cons it (f-filename it)) paths)) + (uniq-filenames-next (-group-by 'cdr uniq-filenames))) + (while (/= files-length (length uniq-filenames-next)) + (setq uniq-filenames-next + (-group-by 'cdr + (--mapcat + (let ((conf-files (cdr it))) + (if (> (length conf-files) 1) + (--map (cons (car it) (concat (f-filename (s-chop-suffix (cdr it) (car it))) (f-path-separator) (cdr it))) conf-files) + conf-files)) + uniq-filenames-next)))) + uniq-filenames-next)) + +(defun f-uniquify (files) + "Return unique suffixes of FILES. + +This function expects no duplicate paths." + (-map 'car (f--uniquify files))) + +(defun f-uniquify-alist (files) + "Return alist mapping FILES to unique suffixes of FILES. + +This function expects no duplicate paths." + (-map 'cadr (f--uniquify files))) + + +;;;; I/O + +(defun f-read-bytes (path) + "Read binary data from PATH. + +Return the binary data as unibyte string." + (with-temp-buffer + (set-buffer-multibyte nil) + (setq buffer-file-coding-system 'binary) + (insert-file-contents-literally path) + (buffer-substring-no-properties (point-min) (point-max)))) + +(defalias 'f-read 'f-read-text) +(defun f-read-text (path &optional coding) + "Read text with PATH, using CODING. + +CODING defaults to `utf-8'. + +Return the decoded text as multibyte string." + (decode-coding-string (f-read-bytes path) (or coding 'utf-8))) + +(defalias 'f-write 'f-write-text) +(defun f-write-text (text coding path) + "Write TEXT with CODING to PATH. + +TEXT is a multibyte string. CODING is a coding system to encode +TEXT with. PATH is a file name to write to." + (f-write-bytes (encode-coding-string text coding) path)) + +(defun f-unibyte-string-p (s) + "Determine whether S is a unibyte string." + (not (multibyte-string-p s))) + +(defun f-write-bytes (data path) + "Write binary DATA to PATH. + +DATA is a unibyte string. PATH is a file name to write to." + (f--write-bytes data path nil)) + +(defalias 'f-append 'f-append-text) +(defun f-append-text (text coding path) + "Append TEXT with CODING to PATH. + +If PATH does not exist, it is created." + (f-append-bytes (encode-coding-string text coding) path)) + +(defun f-append-bytes (data path) + "Append binary DATA to PATH. + +If PATH does not exist, it is created." + (f--write-bytes data path :append)) + +(defun f--write-bytes (data filename append) + "Write binary DATA to FILENAME. +If APPEND is non-nil, append the DATA to the existing contents." + (f--destructive filename + (unless (f-unibyte-string-p data) + (signal 'wrong-type-argument (list 'f-unibyte-string-p data))) + (let ((coding-system-for-write 'binary) + (write-region-annotate-functions nil) + (write-region-post-annotation-function nil)) + (write-region data nil filename append :silent) + nil))) + + +;;;; Destructive + +(defun f-mkdir (&rest dirs) + "Create directories DIRS." + (let (path) + (-each + dirs + (lambda (dir) + (setq path (f-expand dir path)) + (unless (f-directory? path) + (f--destructive path (make-directory path))))))) + +(defun f-delete (path &optional force) + "Delete PATH, which can be file or directory. + +If FORCE is t, a directory will be deleted recursively." + (f--destructive path + (if (or (f-file? path) (f-symlink? path)) + (delete-file path) + (delete-directory path force)))) + +(defun f-symlink (source path) + "Create a symlink to SOURCE from PATH." + (f--destructive path (make-symbolic-link source path))) + +(defun f-move (from to) + "Move or rename FROM to TO. +If TO is a directory name, move FROM into TO." + (f--destructive to (rename-file from to t))) + +(defun f-copy (from to) + "Copy file or directory FROM to TO. +If FROM names a directory and TO is a directory name, copy FROM +into TO as a subdirectory." + (f--destructive to + (if (f-file? from) + (copy-file from to) + ;; The behavior of `copy-directory' differs between Emacs 23 and + ;; 24 in that in Emacs 23, the contents of `from' is copied to + ;; `to', while in Emacs 24 the directory `from' is copied to + ;; `to'. We want the Emacs 24 behavior. + (if (> emacs-major-version 23) + (copy-directory from to) + (if (f-dir? to) + (progn + (apply 'f-mkdir (f-split to)) + (let ((new-to (f-expand (f-filename from) to))) + (copy-directory from new-to))) + (copy-directory from to)))))) + +(defun f-copy-contents (from to) + "Copy contents in directory FROM, to directory TO." + (unless (f-exists? to) + (error "Cannot copy contents to non existing directory %s" to)) + (unless (f-dir? from) + (error "Cannot copy contents as %s is a file" from)) + (--each (f-entries from) + (f-copy it (file-name-as-directory to)))) + +(defun f-touch (path) + "Update PATH last modification date or create if it does not exist." + (f--destructive path + (if (f-file? path) + (set-file-times path) + (f-write-bytes "" path)))) + + +;;;; Predicates + +(defun f-exists? (path) + "Return t if PATH exists, false otherwise." + (file-exists-p path)) + +(defalias 'f-exists-p 'f-exists?) + +(defalias 'f-dir? 'f-directory?) +(defalias 'f-dir-p 'f-dir?) + +(defun f-directory? (path) + "Return t if PATH is directory, false otherwise." + (file-directory-p path)) + +(defalias 'f-directory-p 'f-directory?) + +(defun f-file? (path) + "Return t if PATH is file, false otherwise." + (file-regular-p path)) + +(defalias 'f-file-p 'f-file?) + +(defun f-symlink? (path) + "Return t if PATH is symlink, false otherwise." + (not (not (file-symlink-p path)))) + +(defalias 'f-symlink-p 'f-symlink?) + +(defun f-readable? (path) + "Return t if PATH is readable, false otherwise." + (file-readable-p path)) + +(defalias 'f-readable-p 'f-readable?) + +(defun f-writable? (path) + "Return t if PATH is writable, false otherwise." + (file-writable-p path)) + +(defalias 'f-writable-p 'f-writable?) + +(defun f-executable? (path) + "Return t if PATH is executable, false otherwise." + (file-executable-p path)) + +(defalias 'f-executable-p 'f-executable?) + +(defun f-absolute? (path) + "Return t if PATH is absolute, false otherwise." + (file-name-absolute-p path)) + +(defalias 'f-absolute-p 'f-absolute?) + +(defun f-relative? (path) + "Return t if PATH is relative, false otherwise." + (not (f-absolute? path))) + +(defalias 'f-relative-p 'f-relative?) + +(defun f-root? (path) + "Return t if PATH is root directory, false otherwise." + (not (f-parent path))) + +(defalias 'f-root-p 'f-root?) + +(defun f-ext? (path &optional ext) + "Return t if extension of PATH is EXT, false otherwise. + +If EXT is nil or omitted, return t if PATH has any extension, +false otherwise. + +The extension, in a file name, is the part that follows the last +'.', excluding version numbers and backup suffixes." + (if ext + (string= (f-ext path) ext) + (not (eq (f-ext path) nil)))) + +(defalias 'f-ext-p 'f-ext?) + +(defalias 'f-equal? 'f-same?) +(defalias 'f-equal-p 'f-equal?) + +(defun f-same? (path-a path-b) + "Return t if PATH-A and PATH-B are references to same file." + (when (and (f-exists? path-a) + (f-exists? path-b)) + (equal + (f-canonical (directory-file-name (f-expand path-a))) + (f-canonical (directory-file-name (f-expand path-b)))))) + +(defalias 'f-same-p 'f-same?) + +(defun f-parent-of? (path-a path-b) + "Return t if PATH-A is parent of PATH-B." + (--when-let (f-parent path-b) + (f-same? path-a it))) + +(defalias 'f-parent-of-p 'f-parent-of?) + +(defun f-child-of? (path-a path-b) + "Return t if PATH-A is child of PATH-B." + (--when-let (f-parent path-a) + (f-same? it path-b))) + +(defalias 'f-child-of-p 'f-child-of?) + +(defun f-ancestor-of? (path-a path-b) + "Return t if PATH-A is ancestor of PATH-B." + (unless (f-same? path-a path-b) + (s-starts-with? (f-full path-a) + (f-full path-b)))) + +(defalias 'f-ancestor-of-p 'f-ancestor-of?) + +(defun f-descendant-of? (path-a path-b) + "Return t if PATH-A is desendant of PATH-B." + (unless (f-same? path-a path-b) + (s-starts-with? (f-full path-b) + (f-full path-a)))) + +(defalias 'f-descendant-of-p 'f-descendant-of?) + +(defun f-hidden? (path) + "Return t if PATH is hidden, nil otherwise." + (unless (f-exists? path) + (error "Path does not exist: %s" path)) + (string= (substring path 0 1) ".")) + +(defalias 'f-hidden-p 'f-hidden?) + +(defun f-empty? (path) + "If PATH is a file, return t if the file in PATH is empty, nil otherwise. +If PATH is directory, return t if directory has no files, nil otherwise." + (if (f-directory? path) + (equal (f-files path nil t) nil) + (= (f-size path) 0))) + +(defalias 'f-empty-p 'f-empty?) + + +;;;; Stats + +(defun f-size (path) + "Return size of PATH. + +If PATH is a file, return size of that file. If PATH is +directory, return sum of all files in PATH." + (if (f-directory? path) + (-sum (-map 'f-size (f-files path nil t))) + (nth 7 (file-attributes path)))) + +(defun f-depth (path) + "Return the depth of PATH. + +At first, PATH is expanded with `f-expand'. Then the full path is used to +detect the depth. +'/' will be zero depth, '/usr' will be one depth. And so on." + (- (length (f-split (f-expand path))) 1)) + + +;;;; Misc + +(defun f-this-file () + "Return path to this file." + (cond + (load-in-progress load-file-name) + ((and (boundp 'byte-compile-current-file) byte-compile-current-file) + byte-compile-current-file) + (:else (buffer-file-name)))) + +(defvar f--path-separator nil + "A variable to cache result of `f-path-separator'.") + +(defun f-path-separator () + "Return path separator." + (or f--path-separator + (setq f--path-separator (substring (f-join "x" "y") 1 2)))) + +(defun f-glob (pattern &optional path) + "Find PATTERN in PATH." + (file-expand-wildcards + (f-join (or path default-directory) pattern))) + +(defun f--collect-entries (path recursive) + (let (result + (entries + (-reject + (lambda (file) + (or + (equal (f-filename file) ".") + (equal (f-filename file) ".."))) + (directory-files path t)))) + (cond (recursive + (-map + (lambda (entry) + (if (f-file? entry) + (setq result (cons entry result)) + (when (f-directory? entry) + (setq result (cons entry result)) + (setq result (append result (f--collect-entries entry recursive)))))) + entries)) + (t (setq result entries))) + result)) + +(defmacro f--entries (path body &optional recursive) + "Anaphoric version of `f-entries'." + `(f-entries + ,path + (lambda (path) + (let ((it path)) + ,body)) + ,recursive)) + +(defun f-entries (path &optional fn recursive) + "Find all files and directories in PATH. + +FN - called for each found file and directory. If FN returns a thruthy +value, file or directory will be included. +RECURSIVE - Search for files and directories recursive." + (let ((entries (f--collect-entries path recursive))) + (if fn (-select fn entries) entries))) + +(defmacro f--directories (path body &optional recursive) + "Anaphoric version of `f-directories'." + `(f-directories + ,path + (lambda (path) + (let ((it path)) + ,body)) + ,recursive)) + +(defun f-directories (path &optional fn recursive) + "Find all directories in PATH. See `f-entries'." + (let ((directories (-select 'f-directory? (f--collect-entries path recursive)))) + (if fn (-select fn directories) directories))) + +(defmacro f--files (path body &optional recursive) + "Anaphoric version of `f-files'." + `(f-files + ,path + (lambda (path) + (let ((it path)) + ,body)) + ,recursive)) + +(defun f-files (path &optional fn recursive) + "Find all files in PATH. See `f-entries'." + (let ((files (-select 'f-file? (f--collect-entries path recursive)))) + (if fn (-select fn files) files))) + +(defmacro f--traverse-upwards (body &optional path) + "Anaphoric version of `f-traverse-upwards'." + `(f-traverse-upwards + (lambda (dir) + (let ((it dir)) + ,body)) + ,path)) + +(defun f-traverse-upwards (fn &optional path) + "Traverse up as long as FN return nil, starting at PATH. + +If FN returns a non-nil value, the path sent as argument to FN is +returned. If no function callback return a non-nil value, nil is +returned." + (unless path + (setq path default-directory)) + (when (f-relative? path) + (setq path (f-expand path))) + (if (funcall fn path) + path + (unless (f-root? path) + (f-traverse-upwards fn (f-parent path))))) + +(defun f-root () + "Return absolute root." + (f-traverse-upwards 'f-root?)) + +(defmacro f-with-sandbox (path-or-paths &rest body) + "Only allow PATH-OR-PATHS and decendants to be modified in BODY." + (declare (indent 1)) + `(let ((paths (if (listp ,path-or-paths) + ,path-or-paths + (list ,path-or-paths)))) + (unwind-protect + (let ((f--guard-paths paths)) + ,@body) + (setq f--guard-paths nil)))) + +(provide 'f) + +;;; f.el ends here diff --git a/elpa/f-20190109.906/f.elc b/elpa/f-20190109.906/f.elc new file mode 100644 index 0000000000000000000000000000000000000000..ae84677438c0261229d2579d6e895e50e61a8f9a GIT binary patch literal 20519 zcmc&+i*p;tc^4^*mf2~WwlmGEovbK36kVQzyTj9N$D$<4QEN+%L?_LdYJCI_B4PlC z-~h=?|M~uY-?zK>06>XyCb5SC?y$S}?e~7|eR}-GgCAeJc5V05Pd_yevdL^TP6u)^ znwsND($CGSbe@m0sfpTmWBKLvXmM_m@z`Xu#b`46Q?kI%`Q2Ul@#K7zn;}*)%RJ4^ z;9{CgMtw8L`uSo$n!d~r@#{Qam}D?W2gW}o?A?ueD{BlgtTD|Nrk_n02?j40!=Q^h z)8Od&gU63e|2&x|{RKcgl*cF2fypz|Pp0N9HRCL)Jj8A#H)%2-kJ7nWoMT`V>vMsE zAM_sq_@V#p?(W_>yI7<_KO3ZG?=)^S@E6`XjY59mU*s-gTr~05!e9Hg9pP?vPUEnF zn~lz%`DUK}aXFf&2J}esb2D2m%rJPlOy+|iozJtmk$>^b>0l(pGNkHc9h5 zc?swqrl9GvzZktr!3*hJ7{O%AMLq)XIcRZ~eZTj@G!J%f-|KYD7bDO;8+^JK1gvxbl03|W^!CRE8S7OtA0=nw^zJWq?+nr*F0m226J2dO z8k;+}KQwnuI|>i@;4q5KG_oa$44IR|27sRM;G8IO|O>;u$631$0tAYbzgpx*u_?zReQgPuZY zd^&Qrc5WV%%=l~Vd~nR~o%{Dm;~V@p#9xHJc;^HB+q{4O_|f(I_+80A8rHEC1j+Q` z^fLp}4}(0Jr1(A}QzX+qAk5}LHpHzvRpcI+**tqWHTme}G#PV0WgZ%ny7d_^Oc+^u zbei$O3s7Voe`7lUzY*WYKMf1@a5)8QLDH37E2zV>X2EDWNT-XyjWeO;v}W71Xc+~UR7~CKdLxnm|7t8t72!X94210?(`GRWS@qHbWxvX;gn+ouT&_|?m zyiIJx{|xLjLbC;CCBE7b5Y>o&e9fYd>MIX)sbN4026>7nC){N=87+e8ay*8~36irs z8!s0?A@{60AZ)d|x~r(uG{=Gw-Iqf+8RX&PXXXx;`xYuCS&kRM0LqeRyx2duyX(=w zVb-vuFo7^1iSZ*1>>O+rRw-`L4DQPPyT&|IB-W=G2&Y#~rMaATXn_6Q@(eMo{K;el z;Pog^vGgOFTe%B!HW7}MSCC;3xc^J|h%3tOYOJ(< ziwr~t@y`t485H>U-^xHWEo($!J0eiDBVIp)v7l0@*)W&SB+$)X8E8AiuT2Je!v^eH zz^oGm=xbGY*KeNgVH?mXMDu6ZPwN*Hh?WY+zwmo|OVozkkK{Y|yuz#Ebt!QQ;QY4& z1rQZWX|MV#`lq;fVcHH^u_$jKqunkeW00mZ+PZ!=nZQL{!Hp&E^AdGe6t2#NXbb8c zj#POzcZdK{anuJ#z)$l>qA<3gkwJX?Dux5d%P!xJuH!QLchNfccHTdYV(8~~bOVcuB0u5P);0jJLvLYdyUo>wJou3d z%QFd3M~nc*Zc(vuDnP@hD7T-;WBB|Dp3eth6WEO0{+xE?Yc7Vr27ixqul_nV#RM38 zjNsAWJ&!ECl}r@c?K3Noy-;& zC6P54SBE)&oy;uMt+1)iiC{54ol>Yo!#NS9si%tjjpfZeI2$L^@4#sqX6zk1m}p=v zFaia^0aSEaESC1}f)Aa2k6Up|H{WTv&C5Q;M5<*eGYx<9`)4RZT9tNM-{o17r)56j z#!6<#!88=@N=AkY>X@a|wXR3Y3y9FA=6RH!ez|$}^9lpqpwX~670z{I#0-?s)Km3c zv31GW**twkTbG|_^93zkyXlZ7Vg*7a>x+!L^3HXZfhEQ$B==4TcY z);^fN6O^v_GNq@-ZTs{v4$aYQmNJC_jd$)m3$vV#5ptVsnj#XNr^$fA`86`(-BZNyx6A~UcR9|Z<+5`d>TL5Lj>mpmR;id@H#EE_gl8NKBu{F z!lSS^@##WL<^kF}JD9-#=}2H`L=~%69|B?Yq3&Q8Iu>Tf|#_E0%RMkDvKR9oOUPp+?wGPoef`q^D`q6v$ z;O=s+xqkGURTxbk^v|pgfODsofSL!b$G z^!SToI;fhtv`Gh8i5WsbCLhgU3AYKcwI&dpS0U5t3eWM3$DiFfw|xB;DJZ^~xMQRn z@+)pip{-%lto93$JaKWO#92V@jAAPfr=0wS_G805#}$|E3f|=UZM9-+5W93#61Z!l zX)?b+PI3WPaGp(E9A&pmV_hBs<%aDtDPlC2e2LzomX!QSULuA1By;lfAH}gR<<~$V zCf7PQO4*zbF$gy`vj$%Vo;qB>ABn^5F5BtgbnjzJ*E6tHI#=6>1TH8Qd7AaTrpGMjiCPZ#tRdf zJYCqUV1m?!qK|%_#q4OBr*kCHsI-~eLHL^o$o>G@F`R$9a=tuMl+)vZZGoCxjMDst z=~{26)oHCp(UHt;fP!gU5=1rEt!)sZZ3*GTSRc()y--@} z8{mCeg=`9bWx1k|>^2nmO3vZ+9M~qB-c`H4yG)omM# zO38U6Kv#3G+=vCzDbcp;*G3viyi-|>+@MYmMk;)Z%u1Wguz+wz9f!p(fW%HG6kZl2 zzK58&pH_0yX~NMRfx_Gxj>pGxZGP*sEYhS2XcOyYzeH z1`*mXNS{8$V&SuqZ{niT^WVfqcIeyiQ3opAdIT-Eq4kuz%3d}SsRG&CQt1<&RZyza z3|)YLN|vgG8qjnHo*aF7e3yl*qp!X?e)5ngXPFd4M;ck_N`vY+R3l-~hf3EeekZUH1!t$E626y(n{*>5SL+N3-v2% z*Y?M}4DID*c{r$K$-~j}rF%?+8UHV5)8T?!{e<69Mw3KYbmJk{7emgnDV`sOKmFOy z@w4ReTF_B(*!hS<{!M>pj*;`D#`T*rS#H?H^B=r8bWOF$rur5}I*EOZ=jTp9~?6Evjp>P@PS6HuzLrOHr0DNO=iMs4S(}zgbyIMZzn~MysMMQHD_6 zc^Ox%RhHz6Mn~#R%`eFzNFR`Uf5Y#{c3L)(I$)V)O6t%}AC;y{X=BawRfTsY7SU9z z)F|?c$#^7LWW}rmF_uOJ4{qWjSIOx1BAY@+;oE8;bPVX)^yQvE{hC}+4p5oMx3||h zXKu1J`9f)8_6JZJWkTRy%pxf*msh6rBf`*eIb%{RCIB@twx;VeVu1mWcL zyEl=chir{?&AR5xj2%UD$eDz+kDfjKl9V`kDh|%cQ}y=?MZr;r=;gsI89SQV(bAhB zw@#kc#ZiWrNkmWKuT7%Q9f_a~#EsuXCHMOeB$Q%UCC9e))YYvMlwMaO288g)%0I|v zC=D`BEUQsPe?cliJ*mSGwV)Rhs+*|T=fa$~YpKYjHUx5c=I2{Cbpu^xfihkHk2n=i zfJ#SfJ}Ugup!ZvhybV*P^OLnnr8*oq{x`a9l_-F7hXqdg5FGg-Nx4ZUMvz}<59d_$hd=o>SO~Tr%@DcfaNr5$xrVF&MLE} zY%xVT^bc@QT}AiZ>;cKHe2gebEM*)`c*%1iLyO9JgDixNsAts` z%HI#jvMz>VWxIGXdGwIFtGGoic9~uh*!^mjk-@lH!fO5vD5F|R=&kOjT5oNoB9F7e zAW@DqlEC-e0=ZkwYg_m5YX@Fr*x1>Td~~}FSqMYzZ`e8__ft5cpScPHv4b!%2l{NW z_JNjY31_iuY!Trm(&jd#EcW|R&gw0$vBKWkxe)M=a@FZ10EZ)HnA87fa3T-l59_K* zJ)0s5!-mWDcY5aQ8IsEC`5873*gj7r@ex!p;Vf!PQxfdJLW-iAwXh^wXWbVWD{VFv zF1DS5``0!cUlE3mDvbZacLWg5bAx{w+G36O_e%=F%}O@UT9w;(lTjw4g^=hQ2XS4> zQ&Tr+LD?X6&btr8X2&%t`bssDOSXef`4s)-$rx4pqCswRk=S!~sj#7F+1rY%`5q}k+IsP(u zktA7;lX(@|W+-*v3baD;83ENL1;(zcz*S(hF8)=(v{UMke&$ln@^m|>3TvyoidjF9 z;QFNnVqfg6K+LKHTj#F=vYS(f*)p#{?8a0c!tAarE35~axumNC?dDtt zv>Q_ex~DDB6`+fe1lnCG&_(}31=H#GNDo{Y>|)ksfES}GphLm0vPgL>fiJEv#kuRn zxC*1VIhTP>zsfghSD}YHyiyi(OF|(6c6W6tou(BNo|AzljP=}RoV5n$A3gd25$s^fzmS&5( zDJIKN4{`Oc>{O7zlzr{%MK@S72Hd5TzuXdeB>B6m-b8RD9Z;lwaGxg&Kuxqcpkxal z4t_t+57iqfF-OPOvo7|qQ7NpE*roMz`mgG<>UYVC;$HmTty_XWL4&)N{%rA}D&A7j zfme7QVx=Ug<4`>l;|j}RGj6Sl1z}XNP-uylHM$;q1gEQ{v5`nOT#6hvB0=Zq8LJW| z=z7YTp_T@DE}|Fr+djt;uBZ=&&9?TiRdkVmgl@!NT5YtJ%Ggc+e1ubQSK5qBS=kGz zTHec+grt^Ym+YmhE!LI2xF_gV+?CylZ+iB+Md{)ySy$VPo3*+hMB5bLR?+{4OiZ<{ z%h3jHZ25wRqXKqqh_tagu|%>~quE@wc*WT}-Dw3FVZzm@M>mUOh3MK#P-wdn=`gLY z^WJ8^qQ;{4iZ-?@>^JJJTKLM-b;p%k*4D2#oaZB)AD$knpgo8pl?OrB zBvi<_4APKDd5V8fnNwXZa_D0-n+^F2N78D^gHMpo*hA_9y)SH5cOBt4jHacA3Ue!9 zx_t*EX&tt@m1CvGGTVs@TuLHa-#B~I+CvW6|}%Gy8&J?R*ka1ZD^U%^~i5rp1`B=dng^8>BOEdx5$mP=%-Y4?TOSg+)J}G^~B= zOzu7~cf#Y{!n17EW@|4Q7Ox3F^Io<)K&iH`2WaFecX#)HwU1S_^7^L~2c_lyp)vcv zTITcOH}=Kr6l0FqJfERe{t}GqCQ2wLs&T60^XDFq?!2k<7rY3!n;K}*Pj+sy>;!(0 zoKUCO*wg9$R3U%R)b#Cd(Az0F!yRc6pnFK_%E93HAFtt{E{JbG`D4>qnD{CKoOovQ z0stMIlVW;=1_Y`w%u_}7%iMY@Q3W_ z+x5{8L4Pkt?wL7_p3+ot3Qh1x`*__rkux*yb%+``P000tkstCsB8aiRW?xk z(4x*$dK^FUG^_y%^`Yn3zTY!@7d-A3mBJ%nKokj*QW4J6f{UOpPmZ5GS(RY9Ta@~# zSL-tUa-5yHIzONjSC(1z_WRdvq6t#O*Czie$Bk7amFeI+j0fluA23f!$V=`+Cv*pD zQR^sdo_Tis;Ol44AOH5a4iIwa<1xg`=haJI=K}{JKI0pL%sn=0f)Q^M(@a=O8yAzx z_>*+<&P}O7vongtCluAf)<>=&f%3urwXH2ZoX$>`>S=eRe*QpFFG-*n0W@%lSx^Eq z7ATntu?=Ki;dao>aD{+u5Q*Ggq0HYb*SK!4& z#q`S?tq;8+E02(%j09#~QGUQ@i^`g>1VEa1^8tPCMvR;X7+1Dc56v|-lCc}sZ}s@e z$+O=}=ZhEOPTaH=DfHYPO_Lc8b>YP;uBfK6Ys)I-vn%qRic+Y%nTK3Wru^QD4$j?C z02@3BD}0Vmu~$3qA0J~tm9PtzUY zT$adWVOLo}c4%Xr$a+A~`j4KN0BQ^DK9G|<($O`f4ixEQ=GPjCXqQ zT35W>5ow*zfup6>xfKDcoMr*nNi2rX=FZOX@%FJ-(<_TOqJa%d>Y7*3)}HrzvGk~m zvW9sk7RII+qc3ER(c+MhduLPT)o2T>W@4tBVtqKp|lSf>%G z4rY*D?=f6eOdRFAs>q?0B~oJ?>rV91Ch!FTE*HJBIz!#^3bsq*Nl7}^A$|pA^sVTY zs0MDr=abHKDgf~$=--0^{Emk8ExpHvUFU5`p6Qny)ZE5Dt z@x8WrIz?9wsDpQD5y8RJX8}K-tL;o}iYjM3f+k$|$}ZY``?@aoVufPn=2vhrF2yUa z70WDxIyTS_#;)kzEn%s0#8!VT$fAK2qjc|^INo}&CS!K`YNpo V3f8|$i*NdR#kaT(k-s|F{eKcJ0d4>Q literal 0 HcmV?d00001 diff --git a/elpa/flycheck-20191027.1608/flycheck-autoloads.el b/elpa/flycheck-20191027.1608/flycheck-autoloads.el new file mode 100644 index 0000000..37d6b72 --- /dev/null +++ b/elpa/flycheck-20191027.1608/flycheck-autoloads.el @@ -0,0 +1,259 @@ +;;; flycheck-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "flycheck" "flycheck.el" (0 0 0 0)) +;;; Generated autoloads from flycheck.el + +(autoload 'flycheck-manual "flycheck" "\ +Open the Flycheck manual. + +\(fn)" t nil) + +(autoload 'flycheck-mode "flycheck" "\ +Minor mode for on-the-fly syntax checking. + +When called interactively, toggle `flycheck-mode'. With prefix +ARG, enable `flycheck-mode' if ARG is positive, otherwise disable +it. + +When called from Lisp, enable `flycheck-mode' if ARG is omitted, +nil or positive. If ARG is `toggle', toggle `flycheck-mode'. +Otherwise behave as if called interactively. + +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. + +\\{flycheck-mode-map} + +\(fn &optional ARG)" t nil) + +(defvar global-flycheck-mode nil "\ +Non-nil if Global Flycheck mode is enabled. +See the `global-flycheck-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-flycheck-mode'.") + +(custom-autoload 'global-flycheck-mode "flycheck" nil) + +(autoload 'global-flycheck-mode "flycheck" "\ +Toggle Flycheck mode in all buffers. +With prefix ARG, enable Global Flycheck mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Flycheck mode is enabled in all buffers where +`flycheck-mode-on-safe' would do it. +See `flycheck-mode' for more information on Flycheck mode. + +\(fn &optional ARG)" t nil) + +(autoload 'flycheck-define-error-level "flycheck" "\ +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. + + 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 BITMAP' + A fringe bitmap symbol denoting the bitmap to use for fringe + indicators for this level. 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. + +`: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'. + +\(fn LEVEL &rest PROPERTIES)" nil nil) + +(function-put 'flycheck-define-error-level 'lisp-indent-function '1) + +(autoload 'flycheck-define-command-checker "flycheck" "\ +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. + +\(fn SYMBOL DOCSTRING &rest PROPERTIES)" nil nil) + +(function-put 'flycheck-define-command-checker 'lisp-indent-function '1) + +(function-put 'flycheck-define-command-checker 'doc-string-elt '2) + +(autoload 'flycheck-def-config-file-var "flycheck" "\ +Define SYMBOL as config file variable for CHECKER, with default FILE-NAME. + +SYMBOL is declared as customizable variable using `defcustom', to +provide a configuration file 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. + +Use this together with the `config-file' form in the `:command' +argument to `flycheck-define-checker'. + +\(fn SYMBOL CHECKER &optional FILE-NAME &rest CUSTOM-ARGS)" nil t) + +(function-put 'flycheck-def-config-file-var 'lisp-indent-function '3) + +(autoload 'flycheck-def-option-var "flycheck" "\ +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'. + +\(fn SYMBOL INIT-VALUE CHECKERS DOCSTRING &rest CUSTOM-ARGS)" nil t) + +(function-put 'flycheck-def-option-var 'lisp-indent-function '3) + +(function-put 'flycheck-def-option-var 'doc-string-elt '4) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flycheck" '("flycheck-" "list-flycheck-errors" "help-flycheck-checker-d"))) + +;;;*** + +;;;### (autoloads nil "flycheck-buttercup" "flycheck-buttercup.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from flycheck-buttercup.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flycheck-buttercup" '("flycheck-buttercup-format-error-list"))) + +;;;*** + +;;;### (autoloads nil "flycheck-ert" "flycheck-ert.el" (0 0 0 0)) +;;; Generated autoloads from flycheck-ert.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flycheck-ert" '("flycheck-er"))) + +;;;*** + +;;;### (autoloads nil nil ("flycheck-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; flycheck-autoloads.el ends here diff --git a/elpa/flycheck-20191027.1608/flycheck-buttercup.el b/elpa/flycheck-20191027.1608/flycheck-buttercup.el new file mode 100644 index 0000000..9802265 --- /dev/null +++ b/elpa/flycheck-20191027.1608/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/elpa/flycheck-20191027.1608/flycheck-ert.el b/elpa/flycheck-20191027.1608/flycheck-ert.el new file mode 100644 index 0000000..b7c2bc0 --- /dev/null +++ b/elpa/flycheck-20191027.1608/flycheck-ert.el @@ -0,0 +1,483 @@ +;;; 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)) + `(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)) + `(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)) + (sleep-for 1)) + (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, + (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-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 (mapcar (apply-partially #'apply #'flycheck-error-new-at) + errors))) + (should (equal (mapcar #'flycheck-error-without-group expected) + (mapcar #'flycheck-error-without-group + flycheck-current-errors))) + ;; Check that related errors are the same + (cl-mapcar (lambda (err1 err2) + (should (equal (mapcar #'flycheck-error-without-group + (flycheck-related-errors err1 expected)) + (mapcar #'flycheck-error-without-group + (flycheck-related-errors err2))))) + expected flycheck-current-errors) + (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 (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) + ;; 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)) + (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) + (signal 'flycheck-ert-suspicious-checker nil)))) + (flycheck-ert-buffer-sync) + (apply #'flycheck-ert-should-errors errors) + (should (= process-hook-called (length errors)))) + (flycheck-ert-ensure-clear)))) + +(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 error %s, but point %s is at error %s" + 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/elpa/flycheck-20191027.1608/flycheck-ert.elc b/elpa/flycheck-20191027.1608/flycheck-ert.elc new file mode 100644 index 0000000000000000000000000000000000000000..1f4f7f5562c7c982346e129832b613ff4fe1045b GIT binary patch literal 23686 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%0DE#0<_cAQmlT!7tt6~D`_{aib=PwxEJlUl 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 +;; 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 + +;; 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)))))) + + ;; 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 + 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 + emacs-lisp + emacs-lisp-checkdoc + 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-mypy + r-lintr + racket + rpm-rpmlint + rst-sphinx + rst + ruby-rubocop + 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) + "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 and warnings. + +This variable controls how Flycheck indicates errors in buffers. +May either be `left-fringe', `right-fringe', or nil. + +If set to `left-fringe' or `right-fringe', indicate errors and +warnings via icons in the left and right fringe respectively. + +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 "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. The following modes are known: + +`columns' + Highlight the error column. If the error does not have a column, + highlight the whole line. + +`symbols' + Highlight the symbol at the error column, if there is any, + otherwise behave like `columns'. This is the default. + +`sexps' + Highlight the expression at the error column, 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) + +(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 + '((((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) + +;; The base faces for the following two faces are inspired by Compilation Mode +(defface flycheck-error-list-line-number + '((t :inherit font-lock-constant-face)) + "Face for line numbers in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "0.16")) + +(defface flycheck-error-list-column-number + '((t :inherit font-lock-constant-face)) + "Face for line numbers in the error list." + :group 'flycheck-faces + :package-version '(flycheck . "0.16")) + +(defface flycheck-error-list-filename + '((t :inherit font-lock-variable-name-face)) + "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-highlight + '((t :inherit highlight)) + "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 the 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 "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-list-p (obj) + "Determine if OBJ is a list of strings." + (and (listp obj) (seq-every-p #'stringp obj))) + +(defun flycheck-symbol-list-p (obj) + "Determine if OBJ is a list of symbols." + (and (listp obj) (seq-every-p #'symbolp obj))) + +(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 have the same path. Or, +- They have the same inode and filesystem numbers, not following symlink. Or, +- After chasing symlinks, they result in the same path. + +This should work even on w32, where Emacs uses file index to +emulate inode (see fstat() in emacs/src/w32.c)." + (or (string= file-a file-b) + (let ((attrs-a (file-attributes file-a)) + (attrs-b (file-attributes file-b))) + (and attrs-a attrs-b ;; Make sure both file-a and file-b exist. + (equal (nth 10 attrs-a) (nth 10 attrs-b)) ;; inode + (equal (nth 11 attrs-a) (nth 11 attrs-b)))) ;; filesystem + (string= (file-chase-links file-a) (file-chase-links 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) + "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 with +`flycheck-temp-prefix' and a random suffix. 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))))) + (push tempfile flycheck-temporaries) + tempfile)) + +(defun flycheck-temp-file-inplace (filename) + "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'. + +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))) + +(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-restriction + (widen) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward pattern nil 'no-error) + (match-string-no-properties 1))))) + +(defun flycheck-buffer-empty-p (&optional buffer) + "Whether a BUFFER is empty. + +If buffer is nil or omitted check the current buffer. + +Return non-nil if so, or nil if the buffer has content." + (<= (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 (file-truename user-emacs-directory)) + (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 line number. + +`column' + matches the column number. + +`(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 + `((line . ,(rx (group-n 2 (one-or-more digit)))) + (column . ,(rx (group-n 3 (one-or-more digit)))) + (file-name flycheck-rx-file-name 0 nil) + (message flycheck-rx-message 0 nil) + (id flycheck-rx-id 0 nil)) + 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))))) + + +;;; 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'." + (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))) + (and (stringp 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. + +A checker is disabled if it is contained in +`flycheck-disabled-checkers'." + (or (memq checker flycheck-disabled-checkers) + (flycheck-automatically-disabled-checker-p checker))) + +(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 wit 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 and shall + return an explanation message for this error as a string, or + 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." + (let* ((enabled (flycheck-checker-get checker 'enabled)) + (shall-enable + (and (not (flycheck-disabled-checker-p checker)) + (or (memq checker flycheck--automatically-enabled-checkers) + (null enabled) + (funcall enabled))))) + (if shall-enable + (cl-pushnew checker flycheck--automatically-enabled-checkers) + (cl-pushnew checker flycheck--automatically-disabled-checkers)) + shall-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. Once a checker has been enabled +or automatically disabled, `flycheck-may-enable-checker' will +always be constant (t or nil respectively). + +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)))) + +(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 "flycheck-define-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")) + (help-setup-xref (list #'flycheck-describe-checker checker) + (called-interactively-p 'interactive)) + (save-excursion + (with-help-window (help-buffer) + (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))) + (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) + (when (flycheck-valid-checker-p + (intern-soft (match-string 1))) + (help-xref-button 1 'help-flycheck-checker-def checker + filename)))))))) + ;; 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 (flycheck-may-enable-checker checker))) + (push (flycheck-verification-result-new + :label "may enable" + :message (if result "yes" "Automatically disabled!") + :face (if result 'success '(bold warning))) + results))) + (when predicate + (let ((result (funcall predicate))) + (push (flycheck-verification-result-new + :label "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-checker-select + :supertype 'help-xref + 'help-function (lambda (buffer checker) + (with-current-buffer buffer + (flycheck-select-checker checker)) + ;; Revert the verify-setup buffer since it is now stale + (revert-buffer)) + 'help-echo "mouse-1, RET: select Flycheck checker" + 'face 'flycheck-verify-select-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)) + (when (with-current-buffer buffer (flycheck-disabled-checker-p checker)) + (insert (propertize " (disabled)" 'face '(bold error)))) + (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 + 'help-args (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-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 (lambda (c) (if (consp c) (cdr c) c)) + (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))) + +(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 (get-buffer-create " *Flycheck checker*") + (with-current-buffer standard-output + (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))) + (help-buffer (get-buffer-create " *Flycheck checkers*"))) + + ;; Print all applicable checkers for this buffer + (with-help-window help-buffer + (with-current-buffer standard-output + (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 + "\nThe following syntax checkers are not registered:\n\n" + 'face '(bold warning))) + (dolist (checker unregistered-checkers) + (princ " - ") + (princ checker) + (princ "\n")) + (princ + "\nTry adding these syntax checkers to `flycheck-checkers'.\n"))) + + (flycheck--verify-print-footer buffer))) + + (with-current-buffer help-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-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) + (if append + (setf (flycheck-checker-get checker 'next-checkers) + (append (flycheck-checker-get checker 'next-checkers) (list next))) + (push next (flycheck-checker-get checker '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-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 + "Minor mode for on-the-fly syntax checking. + +When called interactively, toggle `flycheck-mode'. With prefix +ARG, enable `flycheck-mode' if ARG is positive, otherwise disable +it. + +When called from Lisp, enable `flycheck-mode' if ARG is omitted, +nil or positive. If ARG is `toggle', toggle `flycheck-mode'. +Otherwise behave as if called interactively. + +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. + +\\{flycheck-mode-map}" + :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) 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-disable-checker (checker &optional enable) + "Interactively disable CHECKER for the current buffer. + +Interactively, 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")) + (if 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. + (progn + (when (memq checker flycheck-disabled-checkers) + (setq flycheck-disabled-checkers + (remq checker flycheck-disabled-checkers)) + (flycheck-buffer)) + (when (memq checker flycheck--automatically-disabled-checkers) + (setq flycheck--automatically-disabled-checkers + (remq checker flycheck--automatically-disabled-checkers)) + (flycheck-buffer))) + (unless (memq checker flycheck-disabled-checkers) + (push checker flycheck-disabled-checkers) + (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--idle-trigger-timer) + (kill-local-variable 'flycheck--idle-trigger-conditions)) + +(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)) + (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 flycheck-error-new) + (:constructor flycheck-error-new-at + (line column + &optional level message + &key checker id group + (filename (buffer-file-name)) + (buffer (current-buffer))))) + "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 number the error refers to, as number. + +`column' (optional) + The column number the error refers to, 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'. + +`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) + +(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-error-line-region (err) + "Get the line region of ERR. + +ERR is a Flycheck error whose region to get. + +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." + (flycheck-error-with-buffer err + (save-restriction + (save-excursion + (widen) + (goto-char (point-min)) + (forward-line (- (flycheck-error-line err) 1)) + ;; We are at the beginning of the line now, so move to the beginning of + ;; its indentation, similar to `back-to-indentation' + (let ((end (line-end-position))) + (skip-syntax-forward " " end) + (backward-prefix-chars) + ;; If the current line is 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) (line-end-position 0) (point)) end)))))) + +(defun flycheck-error-column-region (err) + "Get the error column region of ERR. + +ERR is a Flycheck error whose region to get. + +Return a cons cell `(BEG . END)' where BEG is the character +before the error column, and END the actual error column, or nil +if ERR has no column." + (flycheck-error-with-buffer err + (save-restriction + (save-excursion + (-when-let (column (flycheck-error-column err)) + (widen) + (goto-char (point-min)) + (forward-line (- (flycheck-error-line err) 1)) + (cond + ((eobp) ; Line beyond EOF + ;; If we are at the end of the file (i.e. the line was beyond the + ;; end of the file), use the very last column in the file. + (cons (- (point-max) 1) (point-max))) + ((eolp) ; Empty line + ;; If the target line is empty, there's no column to highlight on + ;; this line, so return the last column of the previous line. + (cons (line-end-position 0) (point))) + (t + ;; The end is either the column offset of the line, or the end of + ;; the line, if the column offset points beyond the end of the + ;; line. + (let ((end (min (+ (point) column) + (+ (line-end-position) 1)))) + (cons (- end 1) end))))))))) + +(defun flycheck-error-thing-region (thing err) + "Get the region of THING at the column of ERR. + +ERR is a Flycheck error whose region to get. THING is a +understood by `thing-at-point'. + +Return a cons cell `(BEG . END)' where BEG is the beginning of +the THING at the error column, and END the end of the symbol. If +ERR has no error column, or if there is no THING at this column, +return nil." + (-when-let (column (car (flycheck-error-column-region err))) + (flycheck-error-with-buffer err + (save-excursion + (save-restriction + (widen) + (goto-char column) + (bounds-of-thing-at-point thing)))))) + +(defun flycheck-error-region-for-mode (err mode) + "Get the region of ERR for the highlighting MODE. + +ERR is a Flycheck error. MODE may be one of the following symbols: + +`columns' + Get the column region of ERR, or the line region if ERR + has no column. + +`symbols' + Get the symbol region of ERR, or the result of `columns', if + there is no sexp at the error column. + +`sexps' + Get the sexp region of ERR, or the result of `columns', if + there is no sexp at the error column. + +`lines' + Return the line region. + +Otherwise signal an error." + ;; Ignoring fields speeds up calls to `line-end-position' in + ;; `flycheck-error-column-region' and `flycheck-error-line-region'. + (let ((inhibit-field-text-motion t)) + (pcase mode + (`columns (or (flycheck-error-column-region err) + (flycheck-error-line-region err))) + (`symbols (or (flycheck-error-thing-region 'symbol err) + (flycheck-error-region-for-mode err 'columns))) + (`sexps (or (flycheck-error-thing-region 'sexp err) + (flycheck-error-region-for-mode err 'columns))) + (`lines (flycheck-error-line-region err)) + (_ (error "Invalid mode %S" 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 (or (flycheck-error-column-region err) + (flycheck-error-line-region err)))) + +(defun flycheck-error-format-message-and-id (err) + "Format the message and id of ERR as human-readable string." + (let ((id (flycheck-error-id err)) + (filename (flycheck-error-filename err))) + (concat (when (and filename (not (equal filename (buffer-file-name)))) + (format "In \"%s\":\n" + (file-relative-name filename default-directory))) + (flycheck-error-message err) + (when id + (format " [%s]" id))))) + +(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* ((line (flycheck-error-line err)) + (column (flycheck-error-column err)) + (level (symbol-name (flycheck-error-level err))) + (checker (symbol-name (flycheck-error-checker err))) + (format `(,@(when with-file-name + (list (flycheck-error-filename err) ":")) + ,(number-to-string line) ":" + ,@(when column (list (number-to-string column) ":")) + ,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. + +Compare by line numbers and then by column numbers." + (let ((line1 (flycheck-error-line err1)) + (line2 (flycheck-error-line err2))) + (if (= line1 line2) + (let ((col1 (flycheck-error-column err1)) + (col2 (flycheck-error-column err2))) + (and col2 + ;; Sort errors for the whole line first + (or (not col1) (< col1 col2)))) + (< line1 line2)))) + +(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 (sort (append errors flycheck-current-errors) + #'flycheck-error-<)) + (overlay-recenter (point-max)) + (seq-do (lambda (err) + (run-hook-with-args-until-success 'flycheck-process-error-functions + err)) + 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)) + (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 +;;;###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. + + 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 BITMAP' + A fringe bitmap symbol denoting the bitmap to use for fringe + indicators for this level. 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. + +`: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-bitmap-double-arrow) + (plist-get properties :fringe-bitmap)) + (setf (get level 'flycheck-fringe-face) + (plist-get properties :fringe-face)) + (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-fringe-bitmap (level) + "Get the fringe bitmap for LEVEL." + (get level 'flycheck-fringe-bitmap-double-arrow)) + +(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-fringe-icon (level side) + "Create the fringe icon for LEVEL at SIDE. + +Return a propertized string that shows a fringe bitmap according +to LEVEL and the given fringe SIDE. + +LEVEL is a Flycheck error level defined with +`flycheck-define-error-level', and SIDE is either `left-fringe' +or `right-fringe'. + +Return a propertized string representing the fringe icon, +intended for use as `before-string' of an overlay to actually +show the icon." + (unless (memq side '(left-fringe right-fringe)) + (error "Invalid fringe side: %S" side)) + (propertize "!" 'display + (list side + (flycheck-error-level-fringe-bitmap level) + (flycheck-error-level-fringe-face level)))) + + +;;; Built-in error levels +(when (fboundp 'define-fringe-bitmap) + (define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow + (vector #b00000000 + #b00000000 + #b00000000 + #b00000000 + #b00000000 + #b10011000 + #b01101100 + #b00110110 + #b00011011 + #b00110110 + #b01101100 + #b10011000 + #b00000000 + #b00000000 + #b00000000 + #b00000000 + #b00000000))) + +(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 + :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow + :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 + :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow + :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 + :fringe-bitmap 'flycheck-fringe-bitmap-double-arrow + :fringe-face 'flycheck-fringe-info + :error-list-face 'flycheck-error-list-info) + + +;;; 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)) + (column (flycheck-error-column 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 column 0) + (setf (flycheck-error-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. + +Use this as `:error-filter' if a syntax checker outputs 0-based +columns." + (seq-do (lambda (err) + (let ((column (flycheck-error-column err))) + (when column + (setf (flycheck-error-column err) + (+ column (or offset 1)))))) + 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 + ;; indendation 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 errror 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 +(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))) + (unless (flycheck-error-level-p level) + (error "Undefined error level: %S" level)) + (setf (overlay-get overlay 'flycheck-overlay) t) + (setf (overlay-get overlay 'flycheck-error) err) + (setf (overlay-get overlay 'category) category) + (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-fringe-icon + level flycheck-indication-mode))) + (setf (overlay-get overlay 'help-echo) #'flycheck-help-echo) + 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." + (mapconcat + (lambda (err) + (when err + (if (flycheck-error-message err) + (flycheck-error-format-message-and-id err) + (format "Unknown %s" (flycheck-error-level err))))) + (reverse errs) "\n\n")) + +(defun flycheck-filter-overlays (overlays) + "Get all Flycheck overlays from OVERLAYS." + (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 overlayed 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 overlayed 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) + (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'." + (when (flycheck-error-p err) + (-if-let (min-level flycheck-navigation-minimum-level) + (<= (flycheck-error-level-severity min-level) + (flycheck-error-level-severity (flycheck-error-level err))) + 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.") + +(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))) + (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." + (when (get-buffer flycheck-error-list-buffer) + (with-current-buffer flycheck-error-list-buffer + ;; Only update the source when required + (unless (eq buffer flycheck-error-list-source-buffer) + (setq flycheck-error-list-source-buffer buffer) + (flycheck-error-list-refresh))))) + +(defun flycheck-error-list-update-source () + "Update the source buffer of the error list." + (unless (eq (current-buffer) (get-buffer flycheck-error-list-buffer)) + ;; We must not update the source buffer, if the current buffer is the error + ;; list itself. + (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-button-goto-error + 'help-echo "mouse-1, RET: goto error" + 'face nil) + +(defun flycheck-error-list-button-goto-error (button) + "Go to the error at BUTTON." + (flycheck-error-list-goto-error (button-start button))) + +(define-button-type 'flycheck-error-list-explain-error + 'action #'flycheck-error-list-button-explain-error + 'help-echo "mouse-1, RET: explain error") + +(defun flycheck-error-list-button-explain-error (button) + "Explain the error at BUTTON." + (flycheck-error-list-explain-error (button-start button))) + +(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" (symbol-name 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)) + (-when-let (buf (get-buffer flycheck-error-list-buffer)) + (with-current-buffer buf + (setq-local flycheck-error-list-minimum-level level)) + (flycheck-error-list-refresh) + (flycheck-error-list-recenter-at (point-min)))) + +(defun flycheck-error-list-reset-filter () + "Remove filters and show all errors in the error list." + (interactive) + (kill-local-variable 'flycheck-error-list-minimum-level)) + +(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, which isn't in ELPA + (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 + (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)) + (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 lists 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) + (let ((current-errors (flycheck-overlay-errors-in (line-beginning-position) + (line-end-position)))) + (with-current-buffer flycheck-error-list-buffer + (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))) + (flycheck-error-list-set-source (current-buffer)) + ;; Reset the error filter + (flycheck-error-list-reset-filter) + ;; Show the error list in a window, and re-select the old window + (display-buffer flycheck-error-list-buffer) + ;; Finally, refresh the error list to show the most recent errors + (flycheck-error-list-refresh)) + +(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 the error at point in minibuffer.") + +(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-display-error-at-point () + "Display the all error messages at point in minibuffer." + (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) + (when flycheck-mode + (-when-let (errors (flycheck-overlay-errors-at (point))) + (flycheck-display-errors errors))))) + +(defun flycheck-display-error-at-point-soon () + "Display the first error message at point in minibuffer delayed." + (flycheck-cancel-error-display-error-at-point-timer) + (when (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 separated by empty +lines, 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 ((messages (seq-map #'flycheck-error-format-message-and-id errors))) + (let ((result (display-message-or-buffer (string-join messages "\n\n") + flycheck-error-message-buffer + 'not-this-window))) + (when (window-live-p result) + (with-current-buffer (window-buffer result) + (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.") + +(defun flycheck-display-error-explanation (explanation) + "Display the EXPLANATION string in a help buffer." + (with-help-window (get-buffer-create flycheck-explain-error-buffer) + (princ explanation))) + + +;;; 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 `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-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-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 `null-device' + first. + +`null-device' + Return the value of `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-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-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 (funcall flycheck-command-wrapper-function + (cons program args))) + ;; 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)) + (setf (process-sentinel process) #'flycheck-handle-signal) + (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) + (flycheck-process-send-buffer process)) + ;; 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))) + ;; 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) + (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. + +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 (/= exit-status 0) (not 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 non-zero \ +exit code %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 a configuration file 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. + +Use this together with the `config-file' form in the `:command' +argument to `flycheck-define-checker'." + ;; FIXME: We should allow multiple config files per checker as well as + ;; multiple checkers per config file + (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 a buffer." checker) + :type '(choice (const :tag "No configuration file" nil) + (string :tag "File name or path")) + :group 'flycheck-config-files + ,@custom-args) + (flycheck-register-config-file-var ',symbol ',checker))) + +(defun flycheck-locate-config-file (filename checker) + "Locate the configuration file FILENAME for CHECKER. + +Locate the configuration file using +`flycheck-locate-config-file-functions'. + +Return the absolute path of the configuration file, or nil if no +configuration file was found." + (-when-let (filepath (run-hook-with-args-until-success + 'flycheck-locate-config-file-functions + filename checker)) + (when (file-exists-p filepath) + filepath))) + +(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))) + (list regexp 1 2 3 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-checker-shell-command (checker) + "Get a shell command for CHECKER. + +Perform substitution in the arguments of CHECKER, but with +`flycheck-substitute-shell-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 (apply #'append + (seq-map + (lambda (arg) + (if (memq arg '(source source-inplace source-original)) + (list (buffer-file-name)) + (flycheck-substitute-argument arg checker))) + (flycheck-checker-arguments checker)))) + (command (mapconcat + #'shell-quote-argument + (funcall flycheck-command-wrapper-function + (cons (flycheck-checker-executable checker) args)) + " "))) + (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 buffers without 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)) + (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 return value of the +function `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) + :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." + (let ((json-array-type 'list)) + (seq-map (lambda (message) + (let-alist message + (flycheck-error-new-at + (+ 1 .startPosition.line) + (+ 1 .startPosition.character) + 'warning .failure + :id .ruleName + :checker checker + :buffer buffer + :filename .name))) + ;; Don't try to parse empty output as JSON + (and (not (string-empty-p output)) + (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/libsyntax/json.rs#L67-L139" + (let ((error-message) + (error-level) + (error-code) + (primary-filename) + (primary-line) + (primary-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)) + (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) + errors))) + + ;; Then we turn children messages into flycheck errors pointing to the + ;; location of the primary span. + (dolist (child children) + (let-alist child + (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 (cdr (assq 'line_start (car .spans))) + primary-line) + (or (cdr (assq 'column_start (car .spans))) + 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-let (replacement + (cdr (assq 'suggested_replacement (car .spans)))) + (format "%s: `%s`" .message replacement) + .message) + :id error-code + :checker checker + :buffer buffer + :filename primary-filename + :group group) + 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. + (unless 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))) + +(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 (json-read) 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'. + (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." + (let ((regexp (car pattern)) + (level (cdr pattern))) + (when (string-match regexp err) + (let ((filename (match-string 1 err)) + (line (match-string 2 err)) + (column (match-string 3 err)) + (message (match-string 4 err)) + (id (match-string 5 err))) + (flycheck-error-new-at + (flycheck-string-to-number-safe line) + (flycheck-string-to-number-safe 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)))))) + +(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 +(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 #'stringp + :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) + +(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 #'stringp + :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 "libc++") + (const :tag "GNU libstdc++" "libstdc++") + (string :tag "Library name")) + :safe #'stringp + :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++ compiles typicall 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 #'stringp + :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 ":" column + ": note: " (message) line-end) + (warning line-start (or "" (file-name)) ":" line ":" 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 ":" 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 #'stringp + :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" + :safe #'stringp) + +(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) + +(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 + ;; TODO: Parse the end column, once Flycheck supports that + ", characters " column "-" (one-or-more digit) ":\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 + (lambda (errors) + (dolist (err (flycheck-sanitize-errors errors)) + (setf (flycheck-error-message err) + (replace-regexp-in-string (rx (1+ (syntax whitespace)) line-end) + "" (flycheck-error-message err) + 'fixedcase 'literal))) + (flycheck-increment-error-columns errors)) + :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 + :safe #'stringp) + +(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 + :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 #'stringp + :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 + (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 'string + :safe #'stringp) + +(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 (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) + :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) + +(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))))) + +(defconst flycheck-emacs-lisp-check-form + (flycheck-prepare-emacs-lisp-form + ;; Keep track of the generated bytecode files, to delete them after byte + ;; compilation. + (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 (buffer-file-name)) + ;; `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 + (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-check-form) + "--" + source-inplace) + :error-patterns + ((error line-start (file-name) ":" line ":" column ":Error:" + (message (zero-or-more not-newline) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + (warning line-start (file-name) ":" line ":" column ":Warning:" + (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) + ":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 () + (and + ;; Ensure that we only check buffers with a backing file. For buffers + ;; without a backing file we cannot guarantee that file names in error + ;; messages are properly resolved, because `byte-compile-file' emits file + ;; names *relative to the directory of the checked file* instead of the + ;; working directory. Hence our backwards-substitution will fail, because + ;; the checker process has a different base directory to resolve relative + ;; file names than the Flycheck code working on the buffer to check. + (buffer-file-name) + ;; Do not check buffers which 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 + ((warning 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)) + +(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 'string + :safe #'stringp + :package-version '(flycheck . "32")) + +(defun flycheck-erlang-rebar3-get-profile () + "Return rebar3 profile. + +Use flycheck-erlang-rebar3-profile if set, otherwise use test profile if +dirname is test or else default." + (cond + (flycheck-erlang-rebar3-profile flycheck-erlang-rebar3-profile) + ((and buffer-file-name + (string= "test" + (file-name-base + (directory-file-name + (file-name-directory buffer-file-name))))) + "test") + (t "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" + :safe #'stringp) + +(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")) + :safe #'stringp + :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) + :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 'string + :safe #'stringp + :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 'string + :safe #'stringp + :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-default-directory (checker) + "Come up with a suitable default directory for Haskell to run CHECKER in. + +In case of `haskell-stack-ghc' checker it is directory with +stack.yaml file. If there's no stack.yaml file in any parent +directory, it will be the directory that \"stack path --project-root\" +command returns. + +For all other checkers, it is the closest parent directory that +contains a cabal file." + (pcase checker + (`haskell-stack-ghc + (or + (when (buffer-file-name) + (flycheck--locate-dominating-file-matching + (file-name-directory (buffer-file-name)) + "stack.*\\.yaml\\'")) + (-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)))) + (_ + (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") + (`literate-haskell-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 literate-haskell-mode) + :next-checkers ((warning . haskell-hlint)) + :working-directory flycheck-haskell--find-default-directory) + +(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") + (`literate-haskell-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 literate-haskell-mode) + :next-checkers ((warning . haskell-hlint)) + :working-directory flycheck-haskell--find-default-directory) + +(flycheck-def-config-file-var flycheck-hlintrc haskell-hlint "HLint.hs" + :safe #'stringp) + +(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 + ": Suggestion: " + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end) + (warning line-start + (file-name) ":" line ":" column + ": Warning: " + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end) + (error line-start + (file-name) ":" line ":" column + ": Error: " + (message (one-or-more (and (one-or-more (not (any ?\n))) ?\n))) + line-end)) + :modes (haskell-mode literate-haskell-mode)) + +(flycheck-def-config-file-var flycheck-tidyrc html-tidy ".tidyrc" + :safe #'stringp) + +(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" + :safe #'stringp) + +(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." + (let* ((executable (flycheck-find-checker-executable 'javascript-eslint)) + (exitcode (and executable + (call-process executable nil nil nil + "--print-config" (or buffer-file-name + "index.js"))))) + (eq exitcode 0))) + +(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)))) + (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))))))) + +(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 ("python" "-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 (lambda () (not (flycheck-buffer-empty-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) ":" line ":" column + (zero-or-one (group "-" (one-or-more digit))) ": " + (message) line-end) + (error line-start "RUNTIME ERROR: " (message) "\n" + (one-or-more space) (file-name) ":" (zero-or-one "(") + line ":" column (zero-or-more not-newline) line-end)) + :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 + :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" + :safe #'stringp) + +(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 '(string :tag "Theme expression") + :safe #'stringp + :package-version '(flycheck . "32-csv")) + +(flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic + ".perlcriticrc" + :safe #'stringp + :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 #'stringp) + +(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) + ;; 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 (lambda () (not (flycheck-buffer-empty-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 + .line + .column + (pcase .severity + (`"suggestion" 'info) + (`"warning" 'warning) + (`"error" 'error) + ;; Default to error + (_ 'error)) + .message + :id .check + :buffer buffer + :checker checker))) + (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))) + (option-list "--proto_path=" flycheck-protoc-import-path concat) + ;; 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))) + +(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) + ;; 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" + :safe #'stringp + :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-find-module (checker module) + "Check if a Python MODULE is available. +CHECKER's executable is assumed to be a Python REPL." + (-when-let* ((py (flycheck-find-checker-executable checker)) + (script (concat "import sys; sys.path.pop(0);" + (format "import %s; print(%s.__file__)" + module module)))) + (with-temp-buffer + (and (eq (ignore-errors (call-process py nil t nil "-c" script)) 0) + (string-trim (buffer-string)))))) + +(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; +this check ensures that we don't break existing code." + (not (string-match-p (rx (or "pylint" "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) "Missing") + :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" + :safe #'stringp) + +(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) + +(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 ("python" + (eval (flycheck-python-module-args 'python-flake8 "flake8")) + "--format=default" + (config-file "--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) + "-") + :standard-input t + :error-filter (lambda (errors) + (let ((errors (flycheck-sanitize-errors errors))) + (seq-map #'flycheck-flake8-fix-error-level errors))) + :error-patterns + ((warning line-start + "stdin:" 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) + +(flycheck-def-config-file-var flycheck-pylintrc python-pylint ".pylintrc" + :safe #'stringp) + +(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")) + +(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 ("python" + (eval (flycheck-python-module-args 'python-pylint "pylint")) + "--reports=n" + "--output-format=text" + (eval (if flycheck-pylint-use-symbolic-id + "--msg-template={path}:{line}:{column}:{C}:{symbol}:{msg}" + "--msg-template={path}:{line}:{column}:{C}:{msg_id}:{msg}")) + (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-filter + (lambda (errors) + (flycheck-sanitize-errors (flycheck-increment-error-columns errors))) + :error-patterns + ((error line-start (file-name) ":" line ":" column ":" + (or "E" "F") ":" + (id (one-or-more (not (any ":")))) ":" + (message) line-end) + (warning line-start (file-name) ":" line ":" column ":" + (or "W" "R") ":" + (id (one-or-more (not (any ":")))) ":" + (message) line-end) + (info line-start (file-name) ":" line ":" column ":" + (or "C" "I") ":" + (id (one-or-more (not (any ":")))) ":" + (message) line-end)) + :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")) + :modes python-mode) + +(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 ("python" "-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) + +(flycheck-def-config-file-var flycheck-python-mypy-ini python-mypy + "mypy.ini" + :safe #'stringp) + +(flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy + "Directory used to write .mypy_cache directories." + :safe #'stringp + :type '(choice + (const :tag "Write to the working directory" nil) + (const :tag "Never write .mypy_cache directories" null-device) + (string :tag "Path")) + :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-ini) + (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 + :next-checkers (python-flake8)) + +(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 (R) + "Whether R has installed the `lintr' library." + (with-temp-buffer + (let ((process-environment (append '("LC_ALL=C") process-environment))) + (call-process R nil t nil + "--slave" "--restore" "--no-save" "-e" + "library('lintr')") + (goto-char (point-min)) + (not (re-search-forward "there is no package called 'lintr'" + nil 'no-error))))) + +(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 (flycheck-checker-executable 'r-lintr)))) + :verify (lambda (checker) + (let ((has-lintr (flycheck-r-has-lintr + (flycheck-checker-executable 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." + (let ((raco (flycheck-find-checker-executable checker))) + (when raco + (with-temp-buffer + (call-process raco nil t nil "expand") + (goto-char (point-min)) + (not (looking-at-p (rx bol (1+ not-newline) + "Unrecognized command: expand" + eol))))))) + +(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://sourceforge.net/projects/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 + ;; Add fake line numbers if they are missing in the lint output + (lambda (errors) + (dolist (err errors) + (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)))) + (with-output-to-string + (call-process "rpmlint" nil standard-output nil "-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 + :safe #'stringp + :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 ": " (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 + :safe #'stringp + :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 + "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)))) + (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)) + (with-output-to-string + (call-process "nix-linter" nil standard-output nil "--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/'." + ;; We need to use source-inplace to properly resolve relative paths in + ;; 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" + :safe #'stringp) + +(flycheck-def-option-var flycheck-rubocop-lint-only nil ruby-rubocop + "Whether to only report code issues in Rubocop. + +When non-nil, only report code issues in Rubocop, via `--lint'. +Otherwise report style issues as well." + :safe #'booleanp + :type 'boolean + :package-version '(flycheck . "0.16")) + +(flycheck-define-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 `http://batsov.com/rubocop/'." + :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 + ((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 (enh-ruby-mode ruby-mode) + :next-checkers ((warning . ruby-reek) + (warning . ruby-rubylint))) + +;; Default to `nil' to let Reek find its configuration file by itself +(flycheck-def-config-file-var flycheck-reekrc ruby-reek nil + :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 + :safe #'stringp) + +(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 'string + :package-version '(flycheck . "0.20") + :safe #'stringp) +(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 'string + :safe #'stringp + :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-rust-error-explainer (error) + "Return an explanation text for the given `flycheck-error' ERROR." + (-when-let (error-code (flycheck-error-id error)) + (with-output-to-string + (call-process "rustc" nil standard-output nil "--explain" error-code)))) + +(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 + (with-output-to-string + (call-process "cargo" nil standard-output nil + "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" + :safe #'stringp + :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 + :safe #'stringp + :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" + :safe #'stringp + :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) + (let* ((executable (flycheck-find-checker-executable checker)) + (reporter-missing + (and executable + (with-temp-buffer + (call-process executable nil t nil + "--require=scss_lint_reporter_checkstyle") + (goto-char (point-min)) + (re-search-forward + flycheck-scss-lint-checkstyle-re + nil 'no-error))))) + (when executable + (list + (flycheck-verification-result-new + :label "checkstyle reporter" + :message (if reporter-missing + "scss_lint_reporter_checkstyle 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 + :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))))))) + +(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)) + :modes (systemd-mode)) + +(flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc" + :safe #'stringp) + +(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 ":\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 + .line + nil + (pcase .type + (`"ERROR" 'error) + (`"WARNING" 'warning) + ;; Default to error + (_ 'error)) + .message + :id .detector + :checker checker + :buffer buffer + :filename (buffer-file-name buffer)))) + (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" + :safe #'stringp) + +;; This needs to be set because textlint plugins are installed seperately, +;; 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" + :safe #'stringp + :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 #'stringp + :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 #'stringp + :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 #'stringp + :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 #'stringp + :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 '(file :tag "XSD schema") + :safe #'stringp + :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 '(file :tag "XSD schema") + :safe #'stringp + :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))) + +(provide 'flycheck) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: + +;;; flycheck.el ends here diff --git a/elpa/flycheck-20191027.1608/flycheck.elc b/elpa/flycheck-20191027.1608/flycheck.elc new file mode 100644 index 0000000000000000000000000000000000000000..7a068cc889e8e33690a502c23f095158ca49a5b1 GIT binary patch literal 491072 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]#VV-jCYzu@O^_MTwtV~nn5rA3 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

<6f68eR#zt{c-f-C-1dPCZKkRt&oTW0V> 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 literal 0 HcmV?d00001 diff --git a/elpa/flycheck-rust-20190319.1546/flycheck-rust-autoloads.el b/elpa/flycheck-rust-20190319.1546/flycheck-rust-autoloads.el new file mode 100644 index 0000000..8ec491f --- /dev/null +++ b/elpa/flycheck-rust-20190319.1546/flycheck-rust-autoloads.el @@ -0,0 +1,30 @@ +;;; flycheck-rust-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "flycheck-rust" "flycheck-rust.el" (0 0 0 0)) +;;; Generated autoloads from flycheck-rust.el + +(autoload 'flycheck-rust-setup "flycheck-rust" "\ +Setup Rust in Flycheck. + +If the current file is part of a Cargo project, configure +Flycheck according to the Cargo project layout. + +\(fn)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flycheck-rust" '("flycheck-rust-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; flycheck-rust-autoloads.el ends here diff --git a/elpa/flycheck-rust-20190319.1546/flycheck-rust-pkg.el b/elpa/flycheck-rust-20190319.1546/flycheck-rust-pkg.el new file mode 100644 index 0000000..152631d --- /dev/null +++ b/elpa/flycheck-rust-20190319.1546/flycheck-rust-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "flycheck-rust" "20190319.1546" "Flycheck: Rust additions and Cargo support" '((emacs "24.1") (flycheck "28") (dash "2.13.0") (seq "2.3") (let-alist "1.0.4")) :commit "a139cd53c5062697e9ed94ad80b803c37d999600" :keywords '("tools" "convenience") :authors '(("Sebastian Wiesner" . "swiesner@lunaryorn.com")) :maintainer '("Sebastian Wiesner" . "swiesner@lunaryorn.com") :url "https://github.com/flycheck/flycheck-rust") diff --git a/elpa/flycheck-rust-20190319.1546/flycheck-rust.el b/elpa/flycheck-rust-20190319.1546/flycheck-rust.el new file mode 100644 index 0000000..c057beb --- /dev/null +++ b/elpa/flycheck-rust-20190319.1546/flycheck-rust.el @@ -0,0 +1,210 @@ +;;; flycheck-rust.el --- Flycheck: Rust additions and Cargo support -*- lexical-binding: t; -*- + +;; Copyright (C) 2016, 2017 fmdkdd +;; Copyright (C) 2014, 2015 Sebastian Wiesner + +;; Author: Sebastian Wiesner +;; URL: https://github.com/flycheck/flycheck-rust +;; Package-Version: 20190319.1546 +;; Keywords: tools, convenience +;; Version: 1.1 +;; Package-Requires: ((emacs "24.1") (flycheck "28") (dash "2.13.0") (seq "2.3") (let-alist "1.0.4")) + +;; 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 Flycheck extension configures Flycheck automatically for the current +;; Cargo project. +;; +;; # Setup +;; +;; (with-eval-after-load 'rust-mode +;; (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)) +;; +;; # Usage +;; +;; Just use Flycheck as usual in your Rust/Cargo projects. + +;;; Code: + +(eval-when-compile + (require 'pcase) + (require 'let-alist)) + +(require 'dash) +(require 'flycheck) +(require 'seq) +(require 'json) + +(defun flycheck-rust-find-manifest (file-name) + "Get the Cargo.toml manifest for FILE-NAME. + +FILE-NAME is the path of a file in a cargo project given as a +string. + +See http://doc.crates.io/guide.html for an introduction to the +Cargo.toml manifest. + +Return the path to the Cargo.toml manifest file, or nil if the +manifest could not be located." + (-when-let (root-dir (locate-dominating-file file-name "Cargo.toml")) + (expand-file-name "Cargo.toml" root-dir))) + +(defun flycheck-rust-dirs-list (start end) + "Return a list of directories from START (inclusive) to END (exclusive). + +E.g., if START is '/a/b/c/d' and END is '/a', return the list +'(/a/b/c/d /a/b/c /a/b) in this order. + +START and END are strings representing file paths. END should be +above START in the file hierarchy; if not, the list stops at the +root of the file hierarchy." + (let ((dirlist) + (dir (expand-file-name start)) + (end (expand-file-name end))) + (while (not (or (equal dir (car dirlist)) ; avoid infinite loop + (file-equal-p dir end))) + (push dir dirlist) + (setq dir (directory-file-name (file-name-directory dir)))) + (nreverse dirlist))) + +(defun flycheck-rust-get-cargo-targets (manifest) + "Return the list of available Cargo targets for the given project. + +MANIFEST is the path to the Cargo.toml file of the project. + +Calls `cargo metadata --no-deps --manifest-path MANIFEST +--format-version 1', parses and collects the targets for the +current workspace, and returns them in a list, or nil if no +targets could be found." + (let ((cargo (funcall flycheck-executable-find "cargo"))) + (unless cargo + (user-error "flycheck-rust cannot find `cargo'. Please \ +make sure that cargo is installed and on your PATH. See \ +http://www.flycheck.org/en/latest/user/troubleshooting.html for \ +more information on setting your PATH with Emacs.")) + ;; metadata contains a list of packages, and each package has a list of + ;; targets. We concatenate all targets, regardless of the package. + (-when-let (packages (let-alist + (with-temp-buffer + (call-process cargo nil '(t nil) nil + "metadata" "--no-deps" + "--manifest-path" manifest + "--format-version" "1") + (goto-char (point-min)) + (let ((json-array-type 'list)) + (json-read))) + .packages)) + (seq-map (lambda (pkg) + (let-alist pkg .targets)) + packages)))) + +(defun flycheck-rust-find-cargo-target (file-name) + "Return the Cargo build target associated with FILE-NAME. + +FILE-NAME is the path of the file that is matched against the +`src_path' value in the list of `targets' returned by `cargo +read-manifest'. + +Return an alist ((KIND . k) (NAME . n) (REQUIRED-FEATURES . rf)) +where KIND is the target kind (lib, bin, test, example or bench), +NAME the target name (usually, the crate name), and REQUIRED-FEATURES is the +optional list of features required to build the selected target. If FILE-NAME +exactly matches a target `src-path', this target is returned. Otherwise, return +the closest matching target, or nil if no targets could be found. + +See http://doc.crates.io/manifest.html#the-project-layout for a +description of the conventional Cargo project layout." + (-when-let* ((manifest (flycheck-rust-find-manifest file-name)) + (packages (flycheck-rust-get-cargo-targets manifest)) + (targets (-flatten-n 1 packages))) + (let ((target + (or + ;; If there is a target that matches the file-name exactly, pick + ;; that one + (seq-find (lambda (target) + (let-alist target (string= file-name .src_path))) + targets) + ;; Otherwise find the closest matching target by walking up the tree + ;; from FILE-NAME and looking for targets in each directory. E.g., + ;; the file 'tests/common/a.rs' will look for a target in + ;; 'tests/common', then in 'tests/', etc. + (car (seq-find + (lambda (pair) + (-let [((&alist 'src_path target-path) . dir) pair] + (file-equal-p dir (file-name-directory target-path)))) + ;; build a list of (target . dir) candidates + (-table-flat + 'cons targets + (flycheck-rust-dirs-list file-name + (file-name-directory manifest))))) + ;; If all else fails, just pick the first target + (car targets)))) + ;; If target is 'custom-build', we pick another target from the same package (see GH-62) + (when (string= "custom-build" (let-alist target (car .kind))) + (setq target (->> packages + ;; find the same package as current build-script buffer + (--find (--any? (equal target it) it)) + (--find (not (equal target it)))))) + (when target + (let-alist target + (seq-filter (lambda (kv) (cdr kv)) + (list (cons 'kind (flycheck-rust-normalize-target-kind .kind)) + (cons 'name .name) + (cons 'required-features .required-features)))))))) + + +(defun flycheck-rust-normalize-target-kind (kinds) + "Return the normalized target name from KIND. + +KIND is a list of target name as returned by `cargo metadata', +which do not necessarily correspond to to target names that can +be passed as argument to `cargo rustc'. + +The normalization returns a valid cargo target based on KINDS." + ;; Assumption: we only care about the first kind name. Multiple kinds only + ;; seem to happen for library crate types, and those all maps to the same + ;; `lib' target. + (pcase (car kinds) + (`"dylib" "lib") + (`"rlib" "lib") + (`"staticlib" "lib") + (`"cdylib" "lib") + (`"proc-macro" "lib") + (_ (car kinds)))) + +;;;###autoload +(defun flycheck-rust-setup () + "Setup Rust in Flycheck. + +If the current file is part of a Cargo project, configure +Flycheck according to the Cargo project layout." + (interactive) + ;; We should avoid raising any error in this function, as in combination + ;; with `global-flycheck-mode' it will render Emacs unusable (see + ;; https://github.com/flycheck/flycheck-rust/issues/40#issuecomment-253760883). + (with-demoted-errors "Error in flycheck-rust-setup: %S" + (-when-let* ((file-name (buffer-file-name)) + (target (flycheck-rust-find-cargo-target file-name))) + (let-alist target + (setq-local flycheck-rust-features .required-features) + (setq-local flycheck-rust-crate-type .kind) + (setq-local flycheck-rust-binary-name .name))))) + +(provide 'flycheck-rust) + +;;; flycheck-rust.el ends here diff --git a/elpa/flycheck-rust-20190319.1546/flycheck-rust.elc b/elpa/flycheck-rust-20190319.1546/flycheck-rust.elc new file mode 100644 index 0000000000000000000000000000000000000000..cc4a5edc948a13888ecaf4f53e6c66ea2e16e199 GIT binary patch literal 5979 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 object 0)) 1 0) + (or n 0))) + +(defvar pos-tip-saved-frame-coordinates '(0 . 0) + "The latest result of `pos-tip-frame-top-left-coordinates'.") + +(defvar pos-tip-frame-offset nil + "The latest result of `pos-tip-calibrate-frame-offset'. This value +is used for non-X graphical environment.") + +(defvar pos-tip-frame-offset-array [nil nil nil nil] + "Array of the results of `pos-tip-calibrate-frame-offset'. They are +recorded only when `pos-tip-frame-top-left-coordinates' is called for a +non-X but graphical frame. + +The 2nd and 4th elements are the values for frames having a menu bar. +The 3rd and 4th elements are the values for frames having a tool bar.") + +(defun pos-tip-frame-top-left-coordinates (&optional frame) + "Return the pixel coordinates of FRAME as a cons cell (LEFT . TOP), +which are relative to top left corner of screen. + +Return nil if failing to acquire the coordinates. + +If FRAME is omitted, use selected-frame. + +Users can also get the frame coordinates by referring the variable +`pos-tip-saved-frame-coordinates' just after calling this function." + (let ((winsys (pos-tip-window-system frame))) + (cond + ((null winsys) + (error "text-only frame: %S" frame)) + ((eq winsys 'x) + (condition-case nil + (with-current-buffer (get-buffer-create " *xwininfo*") + (let ((case-fold-search nil)) + (buffer-disable-undo) + (erase-buffer) + (call-process shell-file-name nil t nil shell-command-switch + (format "xwininfo -display %s -id %s" + (frame-parameter frame 'display) + (frame-parameter frame 'window-id))) + (goto-char (point-min)) + (search-forward "\n Absolute") + (setq pos-tip-saved-frame-coordinates + (cons (string-to-number (buffer-substring-no-properties + (search-forward "X: ") + (line-end-position))) + (string-to-number (buffer-substring-no-properties + (search-forward "Y: ") + (line-end-position))))))) + (error nil))) + (t + (let* ((index (+ (pos-tip-normalize-natnum + (frame-parameter frame 'menu-bar-lines) 0) + (pos-tip-normalize-natnum + (frame-parameter frame 'tool-bar-lines) 1))) + (offset (or (aref pos-tip-frame-offset-array index) + (aset pos-tip-frame-offset-array index + (pos-tip-calibrate-frame-offset frame))))) + (if offset + (setq pos-tip-saved-frame-coordinates + (cons (+ (eval (frame-parameter frame 'left)) + (car offset)) + (+ (eval (frame-parameter frame 'top)) + (cdr offset)))))))))) + +(defun pos-tip-frame-relative-position + (frame1 frame2 &optional w32-frame frame-coord1 frame-coord2) + "Return the pixel coordinates of FRAME1 relative to FRAME2 +as a cons cell (LEFT . TOP). + +W32-FRAME non-nil means both of frames are under `w32' window system. + +FRAME-COORD1 and FRAME-COORD2, if given, specify the absolute +coordinates of FRAME1 and FRAME2, respectively, which make the +calculations faster if the frames have different heights of menu bars +and tool bars." + (if (and (eq (pos-tip-normalize-natnum + (frame-parameter frame1 'menu-bar-lines)) + (pos-tip-normalize-natnum + (frame-parameter frame2 'menu-bar-lines))) + (or w32-frame + (eq (pos-tip-normalize-natnum + (frame-parameter frame1 'tool-bar-lines)) + (pos-tip-normalize-natnum + (frame-parameter frame2 'tool-bar-lines))))) + (cons (- (eval (frame-parameter frame1 'left)) + (eval (frame-parameter frame2 'left))) + (- (eval (frame-parameter frame1 'top)) + (eval (frame-parameter frame2 'top)))) + (unless frame-coord1 + (setq frame-coord1 (let (pos-tip-saved-frame-coordinates) + (pos-tip-frame-top-left-coordinates frame1)))) + (unless frame-coord2 + (setq frame-coord2 (let (pos-tip-saved-frame-coordinates) + (pos-tip-frame-top-left-coordinates frame2)))) + (cons (- (car frame-coord1) (car frame-coord2)) + (- (cdr frame-coord1) (cdr frame-coord2))))) + +(defvar pos-tip-upperside-p nil + "Non-nil indicates the latest result of `pos-tip-compute-pixel-position' +was upper than the location specified by the arguments.") + +(defvar pos-tip-w32-saved-max-width-height nil + "Display pixel size effective for showing tooltip in MS-Windows desktop. +This doesn't include the taskbar area, so isn't same as actual display size.") + +(defun pos-tip-compute-pixel-position + (&optional pos window pixel-width pixel-height frame-coordinates dx dy) + "Return pixel position of POS in WINDOW like (X . Y), which indicates +the absolute or relative coordinates of bottom left corner of the object. + +Omitting POS and WINDOW means use current position and selected window, +respectively. + +If PIXEL-WIDTH and PIXEL-HEIGHT are given, this function assumes these +values as the size of small window like tooltip which is located around the +object at POS. These values are used to adjust the location in order that +the tooltip won't disappear by sticking out of the display. By referring +the variable `pos-tip-upperside-p' after calling this function, user can +examine whether the tooltip will be located above the specified position. + +If FRAME-COORDINATES is omitted or nil, automatically obtain the absolute +coordinates of the top left corner of frame which WINDOW is on. Here, +`top left corner of frame' represents the origin of `window-pixel-edges' +and its coordinates are essential for calculating the return value as +absolute coordinates. If a cons cell like (LEFT . TOP), specifies the +frame absolute location and makes the calculation slightly faster, but can +be used only when it's clear that frame is in the specified position. Users +can get the latest values of frame coordinates for using in the next call +by referring the variable `pos-tip-saved-frame-coordinates' just after +calling this function. Otherwise, FRAME-COORDINATES `relative' means return +pixel coordinates of the object relative to the top left corner of the frame. +This is the same effect as `pos-tip-use-relative-coordinates' is non-nil. + +DX specifies horizontal offset in pixel. + +DY specifies vertical offset in pixel. This makes the calculations done +without considering the height of object at POS, so the object might be +hidden by the tooltip." + (let* ((frame (window-frame (or window (selected-window)))) + (w32-frame (eq (pos-tip-window-system frame) 'w32)) + (relative (or pos-tip-use-relative-coordinates + (eq frame-coordinates 'relative) + (and w32-frame + (null pos-tip-w32-saved-max-width-height)))) + (frame-coord (or (and relative '(0 . 0)) + frame-coordinates + (pos-tip-frame-top-left-coordinates frame) + (progn + (setq relative t + pos-tip-use-relative-coordinates t) + '(0 . 0)))) + (posn (posn-at-point (or pos (window-point window)) window)) + (line (cdr (posn-actual-col-row posn))) + (line-height (and line + (or (window-line-height line window) + (and (redisplay t) + (window-line-height line window))))) + (x-y (or (posn-x-y posn) + (let ((geom (pos-visible-in-window-p + (or pos (window-point window)) window t))) + (and geom (cons (car geom) (cadr geom)))) + '(0 . 0))) + (x (+ (car frame-coord) + (car (window-inside-pixel-edges window)) + (car x-y) + (or dx 0))) + (y0 (+ (cdr frame-coord) + (cadr (window-pixel-edges window)) + (or (nth 2 line-height) (cdr x-y)))) + (y (+ y0 + (or dy + (car line-height) + (with-current-buffer (window-buffer window) + (cond + ;; `posn-object-width-height' returns an incorrect value + ;; when the header line is displayed (Emacs bug #4426). + ((and posn + (null header-line-format)) + (cdr (posn-object-width-height posn))) + ((and (bound-and-true-p text-scale-mode) + (not (zerop (with-no-warnings + text-scale-mode-amount)))) + (round (* (frame-char-height frame) + (with-no-warnings + (expt text-scale-mode-step + text-scale-mode-amount))))) + (t + (frame-char-height frame))))))) + xmax ymax) + (cond + (relative + (setq xmax (frame-pixel-width frame) + ymax (frame-pixel-height frame))) + (w32-frame + (setq xmax (car pos-tip-w32-saved-max-width-height) + ymax (cdr pos-tip-w32-saved-max-width-height))) + (t + (setq xmax (x-display-pixel-width frame) + ymax (x-display-pixel-height frame)))) + (setq pos-tip-upperside-p (> (+ y (or pixel-height 0)) + ymax)) + (cons (max 0 (min x (- xmax (or pixel-width 0)))) + (max 0 (if pos-tip-upperside-p + (- (if dy ymax y0) (or pixel-height 0)) + y))))) + +(defun pos-tip-cancel-timer () + "Cancel timeout of tooltip." + (mapc (lambda (timer) + (if (eq (aref timer 5) 'x-hide-tip) + (cancel-timer timer))) + timer-list)) + +(defun pos-tip-avoid-mouse (left right top bottom &optional frame) + "Move out mouse pointer if it is inside region (LEFT RIGHT TOP BOTTOM) +in FRAME. Return new mouse position like (FRAME . (X . Y))." + (unless frame + (setq frame (selected-frame))) + (let* ((mpos (with-selected-window (frame-selected-window frame) + (mouse-pixel-position))) + (mframe (pop mpos)) + (mx (car mpos)) + (my (cdr mpos))) + (when (and (eq mframe frame) + (numberp mx)) + (let* ((large-number (+ (frame-pixel-width frame) (frame-pixel-height frame))) + (dl (if (> left 2) + (1+ (- mx left)) + large-number)) + (dr (if (< (1+ right) (frame-pixel-width frame)) + (- right mx) + large-number)) + (dt (if (> top 2) + (1+ (- my top)) + large-number)) + (db (if (< (1+ bottom) (frame-pixel-height frame)) + (- bottom my) + large-number)) + (d (min dl dr dt db))) + (when (> d -2) + (cond + ((= d dl) + (setq mx (- left 2))) + ((= d dr) + (setq mx (1+ right))) + ((= d dt) + (setq my (- top 2))) + (t + (setq my (1+ bottom)))) + (set-mouse-pixel-position frame mx my) + (sit-for 0.0001)))) + (cons mframe (and mpos (cons mx my))))) + +(defun pos-tip-compute-foreground-color (tip-color) + "Compute the foreground color to use for tooltip. + +TIP-COLOR is a face or a cons cell like (FOREGROUND-COLOR . BACKGROUND-COLOR). +If it is nil, use `pos-tip-foreground-color' or the foreground color of the +`tooltip' face." + (or (and (facep tip-color) + (face-attribute tip-color :foreground)) + (car-safe tip-color) + pos-tip-foreground-color + (face-foreground 'tooltip))) + +(defun pos-tip-compute-background-color (tip-color) + "Compute the background color to use for tooltip. + +TIP-COLOR is a face or a cons cell like (FOREGROUND-COLOR . BACKGROUND-COLOR). +If it is nil, use `pos-tip-background-color' or the background color of the +`tooltip' face." + (or (and (facep tip-color) + (face-attribute tip-color :background)) + (cdr-safe tip-color) + pos-tip-background-color + (face-background 'tooltip))) + +(defun pos-tip-show-no-propertize + (string &optional tip-color pos window timeout pixel-width pixel-height frame-coordinates dx dy) + "Show STRING in a tooltip at POS in WINDOW. +Analogous to `pos-tip-show' except don't propertize STRING by `pos-tip' face. + +PIXEL-WIDTH and PIXEL-HEIGHT specify the size of tooltip, if given. These +are used to adjust the tooltip position in order that it doesn't disappear by +sticking out of the display, and also used to prevent it from vanishing by +overlapping with mouse pointer. + +Note that this function itself doesn't calculate tooltip size because the +character width and height specified by faces are unknown. So users should +calculate PIXEL-WIDTH and PIXEL-HEIGHT by using `pos-tip-tooltip-width' and +`pos-tip-tooltip-height', or use `pos-tip-show' instead, which can +automatically calculate tooltip size. + +See `pos-tip-show' for details. + +Example: + +\(defface my-tooltip + '((t + :background \"gray85\" + :foreground \"black\" + :inherit variable-pitch)) + \"Face for my tooltip.\") + +\(defface my-tooltip-highlight + '((t + :background \"blue\" + :foreground \"white\" + :inherit my-tooltip)) + \"Face for my tooltip highlighted.\") + +\(let ((str (propertize \" foo \\n bar \\n baz \" 'face 'my-tooltip))) + (put-text-property 6 11 'face 'my-tooltip-highlight str) + (pos-tip-show-no-propertize str 'my-tooltip))" + (unless window + (setq window (selected-window))) + (let* ((frame (window-frame window)) + (winsys (pos-tip-window-system frame)) + (x-frame (eq winsys 'x)) + (w32-frame (eq winsys 'w32)) + (relative (or pos-tip-use-relative-coordinates + (eq frame-coordinates 'relative) + (and w32-frame + (null pos-tip-w32-saved-max-width-height)))) + (x-y (prog1 + (pos-tip-compute-pixel-position pos window + pixel-width pixel-height + frame-coordinates dx dy) + (if pos-tip-use-relative-coordinates + (setq relative t)))) + (ax (car x-y)) + (ay (cdr x-y)) + (rx (if relative ax (- ax (car pos-tip-saved-frame-coordinates)))) + (ry (if relative ay (- ay (cdr pos-tip-saved-frame-coordinates)))) + (retval (cons rx ry)) + (fg (pos-tip-compute-foreground-color tip-color)) + (bg (pos-tip-compute-background-color tip-color)) + (use-dxdy (or relative + (not x-frame))) + (spacing (frame-parameter frame 'line-spacing)) + (border (ash (+ pos-tip-border-width + pos-tip-internal-border-width) + 1)) + (x-max-tooltip-size + (cons (+ (if x-frame 1 0) + (/ (- (or pixel-width + (cond + (relative + (frame-pixel-width frame)) + (w32-frame + (car pos-tip-w32-saved-max-width-height)) + (t + (x-display-pixel-width frame)))) + border) + (frame-char-width frame))) + (/ (- (or pixel-height + (x-display-pixel-height frame)) + border) + (frame-char-height frame)))) + (mpos (with-selected-window window (mouse-pixel-position))) + (mframe (car mpos)) + default-frame-alist) + (if (or relative + (and use-dxdy + (null (cadr mpos)))) + (unless (and (cadr mpos) + (eq mframe frame)) + (let* ((edges (window-inside-pixel-edges (cadr (window-list frame)))) + (mx (ash (+ (pop edges) (cadr edges)) -1)) + (my (ash (+ (pop edges) (cadr edges)) -1))) + (setq mframe frame) + (set-mouse-pixel-position mframe mx my) + (sit-for 0.0001))) + (when (and (cadr mpos) + (not (eq mframe frame))) + (let ((rel-coord (pos-tip-frame-relative-position frame mframe w32-frame + frame-coordinates))) + (setq rx (+ rx (car rel-coord)) + ry (+ ry (cdr rel-coord)))))) + (and pixel-width pixel-height + (setq mpos (pos-tip-avoid-mouse rx (+ rx pixel-width + (if w32-frame 3 0)) + ry (+ ry pixel-height) + mframe))) + (x-show-tip string mframe + `((border-width . ,pos-tip-border-width) + (internal-border-width . ,pos-tip-internal-border-width) + ,@(and (not use-dxdy) `((left . ,ax) + (top . ,ay))) + (font . ,(frame-parameter frame 'font)) + ,@(and spacing `((line-spacing . ,spacing))) + ,@(and (stringp fg) `((foreground-color . ,fg))) + ,@(and (stringp bg) `((background-color . ,bg)))) + (and timeout (> timeout 0) timeout) + (and use-dxdy (- rx (cadr mpos))) + (and use-dxdy (- ry (cddr mpos)))) + (if (and timeout (<= timeout 0)) + (pos-tip-cancel-timer)) + retval)) + +(defun pos-tip-split-string (string &optional width margin justify squeeze max-rows) + "Split STRING into fixed width strings. Return a list of these strings. + +WIDTH specifies the width of filling each paragraph. WIDTH nil means use +the width of currently selected frame. Note that this function doesn't add any +padding characters at the end of each row. + +MARGIN, if non-nil, specifies left margin width which is the number of spece +characters to add at the beginning of each row. + +The optional fourth argument JUSTIFY specifies which kind of justification +to do: `full', `left', `right', `center', or `none'. A value of t means handle +each paragraph as specified by its text properties. Omitting JUSTIFY means +don't perform justification, word wrap and kinsoku shori (禁則処理). + +SQUEEZE nil means leave whitespaces other than line breaks untouched. + +MAX-ROWS, if given, specifies maximum number of elements of return value. +The elements exceeding this number are discarded." + (with-temp-buffer + (let* ((tab-width (or pos-tip-tab-width tab-width)) + (fill-column (or width (frame-width))) + (left-margin (or margin 0)) + (kinsoku-limit 1) + indent-tabs-mode + row rows) + (insert string) + (untabify (point-min) (point-max)) + (if justify + (fill-region (point-min) (point-max) justify (not squeeze)) + (setq margin (make-string left-margin ?\s))) + (goto-char (point-min)) + (while (prog2 + (let ((line (buffer-substring + (point) (progn (end-of-line) (point))))) + (if justify + (push line rows) + (while (progn + (setq line (concat margin line) + row (truncate-string-to-width line fill-column)) + (push row rows) + (if (not (= (length row) (length line))) + (setq line (substring line (length row)))))))) + (< (point) (point-max)) + (beginning-of-line 2))) + (nreverse (if max-rows + (last rows max-rows) + rows))))) + +(defun pos-tip-fill-string (string &optional width margin justify squeeze max-rows) + "Fill each of the paragraphs in STRING. + +WIDTH specifies the width of filling each paragraph. WIDTH nil means use +the width of currently selected frame. Note that this function doesn't add any +padding characters at the end of each row. + +MARGIN, if non-nil, specifies left margin width which is the number of spece +characters to add at the beginning of each row. + +The optional fourth argument JUSTIFY specifies which kind of justification +to do: `full', `left', `right', `center', or `none'. A value of t means handle +each paragraph as specified by its text properties. Omitting JUSTIFY means +don't perform justification, word wrap and kinsoku shori (禁則処理). + +SQUEEZE nil means leave whitespaces other than line breaks untouched. + +MAX-ROWS, if given, specifies maximum number of rows. The rows exceeding +this number are discarded." + (if justify + (with-temp-buffer + (let* ((tab-width (or pos-tip-tab-width tab-width)) + (fill-column (or width (frame-width))) + (left-margin (or margin 0)) + (kinsoku-limit 1) + indent-tabs-mode) + (insert string) + (untabify (point-min) (point-max)) + (fill-region (point-min) (point-max) justify (not squeeze)) + (if max-rows + (buffer-substring (goto-char (point-min)) + (line-end-position max-rows)) + (buffer-string)))) + (mapconcat 'identity + (pos-tip-split-string string width margin nil nil max-rows) + "\n"))) + +(defun pos-tip-truncate-string (string width height) + "Truncate each line of STRING to WIDTH and discard lines exceeding HEIGHT." + (with-temp-buffer + (insert string) + (goto-char (point-min)) + (let ((nrow 0) + rows) + (while (and (< nrow height) + (prog2 + (push (truncate-string-to-width + (buffer-substring (point) (progn (end-of-line) (point))) + width) + rows) + (< (point) (point-max)) + (beginning-of-line 2) + (setq nrow (1+ nrow))))) + (mapconcat 'identity (nreverse rows) "\n")))) + +(defun pos-tip-string-width-height (string) + "Count columns and rows of STRING. Return a cons cell like (WIDTH . HEIGHT). +The last empty line of STRING is ignored. + +Example: + +\(pos-tip-string-width-height \"abc\\nあいう\\n123\") +;; => (6 . 3)" + (with-temp-buffer + (insert string) + (goto-char (point-min)) + (end-of-line) + (let ((width (current-column)) + (height (if (eq (char-before (point-max)) ?\n) 0 1))) + (while (< (point) (point-max)) + (end-of-line 2) + (setq width (max (current-column) width) + height (1+ height))) + (cons width height)))) + +(defun pos-tip-x-display-width (&optional frame) + "Return maximum column number in tooltip which occupies the full width +of display. Omitting FRAME means use display that selected frame is in." + (1+ (/ (x-display-pixel-width frame) (frame-char-width frame)))) + +(defun pos-tip-x-display-height (&optional frame) + "Return maximum row number in tooltip which occupies the full height +of display. Omitting FRAME means use display that selected frame is in." + (1+ (/ (x-display-pixel-height frame) (frame-char-height frame)))) + +(defun pos-tip-tooltip-width (width char-width) + "Calculate tooltip pixel width." + (+ (* width char-width) + (ash (+ pos-tip-border-width + pos-tip-internal-border-width) + 1))) + +(defun pos-tip-tooltip-height (height char-height &optional frame) + "Calculate tooltip pixel height." + (let ((spacing (or (default-value 'line-spacing) + (frame-parameter frame 'line-spacing)))) + (+ (* height (+ char-height + (cond + ((integerp spacing) + spacing) + ((floatp spacing) + (truncate (* (frame-char-height frame) + spacing))) + (t 0)))) + (ash (+ pos-tip-border-width + pos-tip-internal-border-width) + 1)))) + +(defun pos-tip-show + (string &optional tip-color pos window timeout width frame-coordinates dx dy) + "Show STRING in a tooltip, which is a small X window, at POS in WINDOW +using frame's default font with TIP-COLOR. + +Return pixel position of tooltip relative to top left corner of frame as +a cons cell like (X . Y). + +TIP-COLOR is a face or a cons cell like (FOREGROUND-COLOR . BACKGROUND-COLOR) +used to specify *only* foreground-color and background-color of tooltip. If +omitted, use `pos-tip-foreground-color' and `pos-tip-background-color' or the +foreground and background color of the `tooltip' face instead. + +Omitting POS and WINDOW means use current position and selected window, +respectively. + +Automatically hide the tooltip after TIMEOUT seconds. Omitting TIMEOUT means +use the default timeout of 5 seconds. Non-positive TIMEOUT means don't hide +tooltip automatically. + +WIDTH, if non-nil, specifies the width of filling each paragraph. + +If FRAME-COORDINATES is omitted or nil, automatically obtain the absolute +coordinates of the top left corner of frame which WINDOW is on. Here, +`top left corner of frame' represents the origin of `window-pixel-edges' +and its coordinates are essential for calculating the absolute coordinates +of the tooltip. If a cons cell like (LEFT . TOP), specifies the frame +absolute location and makes the calculation slightly faster, but can be +used only when it's clear that frame is in the specified position. Users +can get the latest values of frame coordinates for using in the next call +by referring the variable `pos-tip-saved-frame-coordinates' just after +calling this function. Otherwise, FRAME-COORDINATES `relative' means use +the pixel coordinates relative to the top left corner of the frame for +displaying the tooltip. This is the same effect as +`pos-tip-use-relative-coordinates' is non-nil. + +DX specifies horizontal offset in pixel. + +DY specifies vertical offset in pixel. This makes the calculations done +without considering the height of object at POS, so the object might be +hidden by the tooltip. + +See also `pos-tip-show-no-propertize'." + (unless window + (setq window (selected-window))) + (let* ((frame (window-frame window)) + (max-width (pos-tip-x-display-width frame)) + (max-height (pos-tip-x-display-height frame)) + (w-h (pos-tip-string-width-height string)) + (fg (pos-tip-compute-foreground-color tip-color)) + (bg (pos-tip-compute-background-color tip-color)) + (frame-font (find-font (font-spec :name (frame-parameter frame 'font)))) + (tip-face-attrs (list :font frame-font :foreground fg :background bg))) + (cond + ((and width + (> (car w-h) width)) + (setq string (pos-tip-fill-string string width nil 'none nil max-height) + w-h (pos-tip-string-width-height string))) + ((or (> (car w-h) max-width) + (> (cdr w-h) max-height)) + (setq string (pos-tip-truncate-string string max-width max-height) + w-h (pos-tip-string-width-height string)))) + (pos-tip-show-no-propertize + (propertize string 'face tip-face-attrs) + tip-color pos window timeout + (pos-tip-tooltip-width (car w-h) (frame-char-width frame)) + (pos-tip-tooltip-height (cdr w-h) (frame-char-height frame) frame) + frame-coordinates dx dy))) + +(defalias 'pos-tip-hide 'x-hide-tip + "Hide pos-tip's tooltip.") + +(defun pos-tip-calibrate-frame-offset (&optional frame) + "Return coordinates of FRAME orign relative to the top left corner of +the FRAME extent, like (LEFT . TOP). The return value is recorded to +`pos-tip-frame-offset'. + +Note that this function does't correctly work for X frame and Emacs 22." + (setq pos-tip-frame-offset nil) + (let* ((window (frame-first-window frame)) + (delete-frame-functions + '((lambda (frame) + (if (equal (frame-parameter frame 'name) "tooltip") + (setq pos-tip-frame-offset + (cons (eval (frame-parameter frame 'left)) + (eval (frame-parameter frame 'top)))))))) + (pos-tip-border-width 0) + (pos-tip-internal-border-width 1) + (rpos (pos-tip-show "" + `(nil . ,(frame-parameter frame 'background-color)) + (window-start window) window + nil nil 'relative nil 0))) + (sit-for 0) + (pos-tip-hide) + (and pos-tip-frame-offset + (setq pos-tip-frame-offset + (cons (- (car pos-tip-frame-offset) + (car rpos) + (eval (frame-parameter frame 'left))) + (- (cdr pos-tip-frame-offset) + (cdr rpos) + (eval (frame-parameter frame 'top)))))))) + +(defun pos-tip-w32-max-width-height (&optional keep-maximize) + "Maximize the currently selected frame temporarily and set +`pos-tip-w32-saved-max-width-height' the effective display size in order +to become possible to calculate the absolute location of tooltip. + +KEEP-MAXIMIZE non-nil means leave the frame maximized. + +Note that this function is usable only in Emacs 23 for MS-Windows." + (interactive) + (unless (eq window-system 'w32) + (error "`pos-tip-w32-max-width-height' can be used only in w32 frame.")) + ;; Maximize frame + (with-no-warnings (w32-send-sys-command 61488)) + (sit-for 0) + (let ((offset (pos-tip-calibrate-frame-offset))) + (prog1 + (setq pos-tip-w32-saved-max-width-height + (cons (frame-pixel-width) + (+ (frame-pixel-height) + (- (cdr offset) (car offset))))) + (if (called-interactively-p 'interactive) + (message "%S" pos-tip-w32-saved-max-width-height)) + (unless keep-maximize + ;; Restore frame + (with-no-warnings (w32-send-sys-command 61728)))))) + + +(provide 'pos-tip) + +;;; +;;; pos-tip.el ends here diff --git a/elpa/pos-tip-20150318.1513/pos-tip.elc b/elpa/pos-tip-20150318.1513/pos-tip.elc new file mode 100644 index 0000000000000000000000000000000000000000..2e55c0fd86aab1d6016d3817746f5d43b96e389c GIT binary patch literal 25301 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 literal 0 HcmV?d00001 diff --git a/elpa/s-20180406.808/s-autoloads.el b/elpa/s-20180406.808/s-autoloads.el new file mode 100644 index 0000000..a232497 --- /dev/null +++ b/elpa/s-20180406.808/s-autoloads.el @@ -0,0 +1,22 @@ +;;; s-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "s" "s.el" (0 0 0 0)) +;;; Generated autoloads from s.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "s" '("s-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; s-autoloads.el ends here diff --git a/elpa/s-20180406.808/s-pkg.el b/elpa/s-20180406.808/s-pkg.el new file mode 100644 index 0000000..7080f87 --- /dev/null +++ b/elpa/s-20180406.808/s-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "s" "20180406.808" "The long lost Emacs string manipulation library." 'nil :commit "03410e6a7a2b11e47e1fea3b7d9899c7df26435e" :keywords '("strings") :authors '(("Magnar Sveen" . "magnars@gmail.com")) :maintainer '("Magnar Sveen" . "magnars@gmail.com")) diff --git a/elpa/s-20180406.808/s.el b/elpa/s-20180406.808/s.el new file mode 100644 index 0000000..d8e359a --- /dev/null +++ b/elpa/s-20180406.808/s.el @@ -0,0 +1,747 @@ +;;; s.el --- The long lost Emacs string manipulation library. + +;; Copyright (C) 2012-2015 Magnar Sveen + +;; Author: Magnar Sveen +;; Version: 1.12.0 +;; Package-Version: 20180406.808 +;; Keywords: strings + +;; 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: + +;; The long lost Emacs string manipulation library. +;; +;; See documentation on https://github.com/magnars/s.el#functions + +;;; Code: + +;; Silence byte-compiler +(defvar ucs-normalize-combining-chars) ; Defined in `ucs-normalize' +(autoload 'slot-value "eieio") + +(defun s-trim-left (s) + "Remove whitespace at the beginning of S." + (declare (pure t) (side-effect-free t)) + (save-match-data + (if (string-match "\\`[ \t\n\r]+" s) + (replace-match "" t t s) + s))) + +(defun s-trim-right (s) + "Remove whitespace at the end of S." + (save-match-data + (declare (pure t) (side-effect-free t)) + (if (string-match "[ \t\n\r]+\\'" s) + (replace-match "" t t s) + s))) + +(defun s-trim (s) + "Remove whitespace at the beginning and end of S." + (declare (pure t) (side-effect-free t)) + (s-trim-left (s-trim-right s))) + +(defun s-collapse-whitespace (s) + "Convert all adjacent whitespace characters to a single space." + (declare (pure t) (side-effect-free t)) + (replace-regexp-in-string "[ \t\n\r]+" " " s)) + +(defun s-split (separator s &optional omit-nulls) + "Split S into substrings bounded by matches for regexp SEPARATOR. +If OMIT-NULLS is non-nil, zero-length substrings are omitted. + +This is a simple wrapper around the built-in `split-string'." + (declare (side-effect-free t)) + (save-match-data + (split-string s separator omit-nulls))) + +(defun s-split-up-to (separator s n &optional omit-nulls) + "Split S up to N times into substrings bounded by matches for regexp SEPARATOR. + +If OMIT-NULLS is non-nil, zero-length substrings are omitted. + +See also `s-split'." + (declare (side-effect-free t)) + (save-match-data + (let ((op 0) + (r nil)) + (with-temp-buffer + (insert s) + (setq op (goto-char (point-min))) + (while (and (re-search-forward separator nil t) + (< 0 n)) + (let ((sub (buffer-substring op (match-beginning 0)))) + (unless (and omit-nulls + (equal sub "")) + (push sub r))) + (setq op (goto-char (match-end 0))) + (setq n (1- n))) + (let ((sub (buffer-substring op (point-max)))) + (unless (and omit-nulls + (equal sub "")) + (push sub r)))) + (nreverse r)))) + +(defun s-lines (s) + "Splits S into a list of strings on newline characters." + (declare (pure t) (side-effect-free t)) + (s-split "\\(\r\n\\|[\n\r]\\)" s)) + +(defun s-join (separator strings) + "Join all the strings in STRINGS with SEPARATOR in between." + (declare (pure t) (side-effect-free t)) + (mapconcat 'identity strings separator)) + +(defun s-concat (&rest strings) + "Join all the string arguments into one string." + (declare (pure t) (side-effect-free t)) + (apply 'concat strings)) + +(defun s-prepend (prefix s) + "Concatenate PREFIX and S." + (declare (pure t) (side-effect-free t)) + (concat prefix s)) + +(defun s-append (suffix s) + "Concatenate S and SUFFIX." + (declare (pure t) (side-effect-free t)) + (concat s suffix)) + +(defun s-repeat (num s) + "Make a string of S repeated NUM times." + (declare (pure t) (side-effect-free t)) + (let (ss) + (while (> num 0) + (setq ss (cons s ss)) + (setq num (1- num))) + (apply 'concat ss))) + +(defun s-chop-suffix (suffix s) + "Remove SUFFIX if it is at end of S." + (declare (pure t) (side-effect-free t)) + (let ((pos (- (length suffix)))) + (if (and (>= (length s) (length suffix)) + (string= suffix (substring s pos))) + (substring s 0 pos) + s))) + +(defun s-chop-suffixes (suffixes s) + "Remove SUFFIXES one by one in order, if they are at the end of S." + (declare (pure t) (side-effect-free t)) + (while suffixes + (setq s (s-chop-suffix (car suffixes) s)) + (setq suffixes (cdr suffixes))) + s) + +(defun s-chop-prefix (prefix s) + "Remove PREFIX if it is at the start of S." + (declare (pure t) (side-effect-free t)) + (let ((pos (length prefix))) + (if (and (>= (length s) (length prefix)) + (string= prefix (substring s 0 pos))) + (substring s pos) + s))) + +(defun s-chop-prefixes (prefixes s) + "Remove PREFIXES one by one in order, if they are at the start of S." + (declare (pure t) (side-effect-free t)) + (while prefixes + (setq s (s-chop-prefix (car prefixes) s)) + (setq prefixes (cdr prefixes))) + s) + +(defun s-shared-start (s1 s2) + "Returns the longest prefix S1 and S2 have in common." + (declare (pure t) (side-effect-free t)) + (let ((search-length (min (length s1) (length s2))) + (i 0)) + (while (and (< i search-length) + (= (aref s1 i) (aref s2 i))) + (setq i (1+ i))) + (substring s1 0 i))) + +(defun s-shared-end (s1 s2) + "Returns the longest suffix S1 and S2 have in common." + (declare (pure t) (side-effect-free t)) + (let* ((l1 (length s1)) + (l2 (length s2)) + (search-length (min l1 l2)) + (i 0)) + (while (and (< i search-length) + (= (aref s1 (- l1 i 1)) (aref s2 (- l2 i 1)))) + (setq i (1+ i))) + ;; If I is 0, then it means that there's no common suffix between + ;; S1 and S2. + ;; + ;; However, since (substring s (- 0)) will return the whole + ;; string, `s-shared-end' should simply return the empty string + ;; when I is 0. + (if (zerop i) + "" + (substring s1 (- i))))) + +(defun s-chomp (s) + "Remove one trailing `\\n`, `\\r` or `\\r\\n` from S." + (declare (pure t) (side-effect-free t)) + (s-chop-suffixes '("\n" "\r") s)) + +(defun s-truncate (len s &optional ellipsis) + "If S is longer than LEN, cut it down and add ELLIPSIS to the end. + +The resulting string, including ellipsis, will be LEN characters +long. + +When not specified, ELLIPSIS defaults to ‘...’." + (declare (pure t) (side-effect-free t)) + (unless ellipsis + (setq ellipsis "...")) + (if (> (length s) len) + (format "%s%s" (substring s 0 (- len (length ellipsis))) ellipsis) + s)) + +(defun s-word-wrap (len s) + "If S is longer than LEN, wrap the words with newlines." + (declare (side-effect-free t)) + (save-match-data + (with-temp-buffer + (insert s) + (let ((fill-column len)) + (fill-region (point-min) (point-max))) + (buffer-substring (point-min) (point-max))))) + +(defun s-center (len s) + "If S is shorter than LEN, pad it with spaces so it is centered." + (declare (pure t) (side-effect-free t)) + (let ((extra (max 0 (- len (length s))))) + (concat + (make-string (ceiling extra 2) ? ) + s + (make-string (floor extra 2) ? )))) + +(defun s-pad-left (len padding s) + "If S is shorter than LEN, pad it with PADDING on the left." + (declare (pure t) (side-effect-free t)) + (let ((extra (max 0 (- len (length s))))) + (concat (make-string extra (string-to-char padding)) + s))) + +(defun s-pad-right (len padding s) + "If S is shorter than LEN, pad it with PADDING on the right." + (declare (pure t) (side-effect-free t)) + (let ((extra (max 0 (- len (length s))))) + (concat s + (make-string extra (string-to-char padding))))) + +(defun s-left (len s) + "Returns up to the LEN first chars of S." + (declare (pure t) (side-effect-free t)) + (if (> (length s) len) + (substring s 0 len) + s)) + +(defun s-right (len s) + "Returns up to the LEN last chars of S." + (declare (pure t) (side-effect-free t)) + (let ((l (length s))) + (if (> l len) + (substring s (- l len) l) + s))) + +(defun s-ends-with? (suffix s &optional ignore-case) + "Does S end with SUFFIX? + +If IGNORE-CASE is non-nil, the comparison is done without paying +attention to case differences. + +Alias: `s-suffix?'" + (declare (pure t) (side-effect-free t)) + (let ((start-pos (- (length s) (length suffix)))) + (and (>= start-pos 0) + (eq t (compare-strings suffix nil nil + s start-pos nil ignore-case))))) + +(defun s-starts-with? (prefix s &optional ignore-case) + "Does S start with PREFIX? + +If IGNORE-CASE is non-nil, the comparison is done without paying +attention to case differences. + +Alias: `s-prefix?'. This is a simple wrapper around the built-in +`string-prefix-p'." + (declare (pure t) (side-effect-free t)) + (string-prefix-p prefix s ignore-case)) + +(defun s--truthy? (val) + (declare (pure t) (side-effect-free t)) + (not (null val))) + +(defun s-contains? (needle s &optional ignore-case) + "Does S contain NEEDLE? + +If IGNORE-CASE is non-nil, the comparison is done without paying +attention to case differences." + (declare (pure t) (side-effect-free t)) + (let ((case-fold-search ignore-case)) + (s--truthy? (string-match-p (regexp-quote needle) s)))) + +(defun s-equals? (s1 s2) + "Is S1 equal to S2? + +This is a simple wrapper around the built-in `string-equal'." + (declare (pure t) (side-effect-free t)) + (string-equal s1 s2)) + +(defun s-less? (s1 s2) + "Is S1 less than S2? + +This is a simple wrapper around the built-in `string-lessp'." + (declare (pure t) (side-effect-free t)) + (string-lessp s1 s2)) + +(defun s-matches? (regexp s &optional start) + "Does REGEXP match S? +If START is non-nil the search starts at that index. + +This is a simple wrapper around the built-in `string-match-p'." + (declare (side-effect-free t)) + (s--truthy? (string-match-p regexp s start))) + +(defun s-blank? (s) + "Is S nil or the empty string?" + (declare (pure t) (side-effect-free t)) + (or (null s) (string= "" s))) + +(defun s-blank-str? (s) + "Is S nil or the empty string or string only contains whitespace?" + (declare (pure t) (side-effect-free t)) + (or (s-blank? s) (s-blank? (s-trim s)))) + +(defun s-present? (s) + "Is S anything but nil or the empty string?" + (declare (pure t) (side-effect-free t)) + (not (s-blank? s))) + +(defun s-presence (s) + "Return S if it's `s-present?', otherwise return nil." + (declare (pure t) (side-effect-free t)) + (and (s-present? s) s)) + +(defun s-lowercase? (s) + "Are all the letters in S in lower case?" + (declare (side-effect-free t)) + (let ((case-fold-search nil)) + (not (string-match-p "[[:upper:]]" s)))) + +(defun s-uppercase? (s) + "Are all the letters in S in upper case?" + (declare (side-effect-free t)) + (let ((case-fold-search nil)) + (not (string-match-p "[[:lower:]]" s)))) + +(defun s-mixedcase? (s) + "Are there both lower case and upper case letters in S?" + (let ((case-fold-search nil)) + (s--truthy? + (and (string-match-p "[[:lower:]]" s) + (string-match-p "[[:upper:]]" s))))) + +(defun s-capitalized? (s) + "In S, is the first letter upper case, and all other letters lower case?" + (declare (side-effect-free t)) + (let ((case-fold-search nil)) + (s--truthy? + (string-match-p "^[[:upper:]][^[:upper:]]*$" s)))) + +(defun s-numeric? (s) + "Is S a number?" + (declare (pure t) (side-effect-free t)) + (s--truthy? + (string-match-p "^[0-9]+$" s))) + +(defun s-replace (old new s) + "Replaces OLD with NEW in S." + (declare (pure t) (side-effect-free t)) + (replace-regexp-in-string (regexp-quote old) new s t t)) + +(defalias 's-replace-regexp 'replace-regexp-in-string) + +(defun s--aget (alist key) + (declare (pure t) (side-effect-free t)) + (cdr (assoc-string key alist))) + +(defun s-replace-all (replacements s) + "REPLACEMENTS is a list of cons-cells. Each `car` is replaced with `cdr` in S." + (declare (pure t) (side-effect-free t)) + (replace-regexp-in-string (regexp-opt (mapcar 'car replacements)) + (lambda (it) (s--aget replacements it)) + s t t)) + +(defun s-downcase (s) + "Convert S to lower case. + +This is a simple wrapper around the built-in `downcase'." + (declare (side-effect-free t)) + (downcase s)) + +(defun s-upcase (s) + "Convert S to upper case. + +This is a simple wrapper around the built-in `upcase'." + (declare (side-effect-free t)) + (upcase s)) + +(defun s-capitalize (s) + "Convert the first word's first character to upper case and the rest to lower case in S." + (declare (side-effect-free t)) + (concat (upcase (substring s 0 1)) (downcase (substring s 1)))) + +(defun s-titleize (s) + "Convert each word's first character to upper case and the rest to lower case in S. + +This is a simple wrapper around the built-in `capitalize'." + (declare (side-effect-free t)) + (capitalize s)) + +(defmacro s-with (s form &rest more) + "Threads S through the forms. Inserts S as the last item +in the first form, making a list of it if it is not a list +already. If there are more forms, inserts the first form as the +last item in second form, etc." + (declare (debug (form &rest [&or (function &rest form) fboundp]))) + (if (null more) + (if (listp form) + `(,(car form) ,@(cdr form) ,s) + (list form s)) + `(s-with (s-with ,s ,form) ,@more))) + +(put 's-with 'lisp-indent-function 1) + +(defun s-index-of (needle s &optional ignore-case) + "Returns first index of NEEDLE in S, or nil. + +If IGNORE-CASE is non-nil, the comparison is done without paying +attention to case differences." + (declare (pure t) (side-effect-free t)) + (let ((case-fold-search ignore-case)) + (string-match-p (regexp-quote needle) s))) + +(defun s-reverse (s) + "Return the reverse of S." + (declare (pure t) (side-effect-free t)) + (save-match-data + (if (multibyte-string-p s) + (let ((input (string-to-list s)) + output) + (require 'ucs-normalize) + (while input + ;; Handle entire grapheme cluster as a single unit + (let ((grapheme (list (pop input)))) + (while (memql (car input) ucs-normalize-combining-chars) + (push (pop input) grapheme)) + (setq output (nconc (nreverse grapheme) output)))) + (concat output)) + (concat (nreverse (string-to-list s)))))) + +(defun s-match-strings-all (regex string) + "Return a list of matches for REGEX in STRING. + +Each element itself is a list of matches, as per +`match-string'. Multiple matches at the same position will be +ignored after the first." + (declare (side-effect-free t)) + (save-match-data + (let ((all-strings ()) + (i 0)) + (while (and (< i (length string)) + (string-match regex string i)) + (setq i (1+ (match-beginning 0))) + (let (strings + (num-matches (/ (length (match-data)) 2)) + (match 0)) + (while (/= match num-matches) + (push (match-string match string) strings) + (setq match (1+ match))) + (push (nreverse strings) all-strings))) + (nreverse all-strings)))) + +(defun s-matched-positions-all (regexp string &optional subexp-depth) + "Return a list of matched positions for REGEXP in STRING. +SUBEXP-DEPTH is 0 by default." + (declare (side-effect-free t)) + (if (null subexp-depth) + (setq subexp-depth 0)) + (save-match-data + (let ((pos 0) result) + (while (and (string-match regexp string pos) + (< pos (length string))) + (let ((m (match-end subexp-depth))) + (push (cons (match-beginning subexp-depth) (match-end subexp-depth)) result) + (setq pos (match-end 0)))) + (nreverse result)))) + +(defun s-match (regexp s &optional start) + "When the given expression matches the string, this function returns a list +of the whole matching string and a string for each matched subexpressions. +If it did not match the returned value is an empty list (nil). + +When START is non-nil the search will start at that index." + (declare (side-effect-free t)) + (save-match-data + (if (string-match regexp s start) + (let ((match-data-list (match-data)) + result) + (while match-data-list + (let* ((beg (car match-data-list)) + (end (cadr match-data-list)) + (subs (if (and beg end) (substring s beg end) nil))) + (setq result (cons subs result)) + (setq match-data-list + (cddr match-data-list)))) + (nreverse result))))) + +(defun s-slice-at (regexp s) + "Slices S up at every index matching REGEXP." + (declare (side-effect-free t)) + (if (= 0 (length s)) (list "") + (save-match-data + (let (i) + (setq i (string-match regexp s 1)) + (if i + (cons (substring s 0 i) + (s-slice-at regexp (substring s i))) + (list s)))))) + +(defun s-split-words (s) + "Split S into list of words." + (declare (side-effect-free t)) + (s-split + "[^[:word:]0-9]+" + (let ((case-fold-search nil)) + (replace-regexp-in-string + "\\([[:lower:]]\\)\\([[:upper:]]\\)" "\\1 \\2" + (replace-regexp-in-string "\\([[:upper:]]\\)\\([[:upper:]][0-9[:lower:]]\\)" "\\1 \\2" s))) + t)) + +(defun s--mapcar-head (fn-head fn-rest list) + "Like MAPCAR, but applies a different function to the first element." + (if list + (cons (funcall fn-head (car list)) (mapcar fn-rest (cdr list))))) + +(defun s-lower-camel-case (s) + "Convert S to lowerCamelCase." + (declare (side-effect-free t)) + (s-join "" (s--mapcar-head 'downcase 'capitalize (s-split-words s)))) + +(defun s-upper-camel-case (s) + "Convert S to UpperCamelCase." + (declare (side-effect-free t)) + (s-join "" (mapcar 'capitalize (s-split-words s)))) + +(defun s-snake-case (s) + "Convert S to snake_case." + (declare (side-effect-free t)) + (s-join "_" (mapcar 'downcase (s-split-words s)))) + +(defun s-dashed-words (s) + "Convert S to dashed-words." + (declare (side-effect-free t)) + (s-join "-" (mapcar 'downcase (s-split-words s)))) + +(defun s-capitalized-words (s) + "Convert S to Capitalized words." + (declare (side-effect-free t)) + (let ((words (s-split-words s))) + (s-join " " (cons (capitalize (car words)) (mapcar 'downcase (cdr words)))))) + +(defun s-titleized-words (s) + "Convert S to Titleized Words." + (declare (side-effect-free t)) + (s-join " " (mapcar 's-titleize (s-split-words s)))) + +(defun s-word-initials (s) + "Convert S to its initials." + (declare (side-effect-free t)) + (s-join "" (mapcar (lambda (ss) (substring ss 0 1)) + (s-split-words s)))) + +;; Errors for s-format +(progn + (put 's-format-resolve + 'error-conditions + '(error s-format s-format-resolve)) + (put 's-format-resolve + 'error-message + "Cannot resolve a template to values")) + +(defun s-format (template replacer &optional extra) + "Format TEMPLATE with the function REPLACER. + +REPLACER takes an argument of the format variable and optionally +an extra argument which is the EXTRA value from the call to +`s-format'. + +Several standard `s-format' helper functions are recognized and +adapted for this: + + (s-format \"${name}\" 'gethash hash-table) + (s-format \"${name}\" 'aget alist) + (s-format \"$0\" 'elt sequence) + +The REPLACER function may be used to do any other kind of +transformation." + (let ((saved-match-data (match-data))) + (unwind-protect + (replace-regexp-in-string + "\\$\\({\\([^}]+\\)}\\|[0-9]+\\)" + (lambda (md) + (let ((var + (let ((m (match-string 2 md))) + (if m m + (string-to-number (match-string 1 md))))) + (replacer-match-data (match-data))) + (unwind-protect + (let ((v + (cond + ((eq replacer 'gethash) + (funcall replacer var extra)) + ((eq replacer 'aget) + (funcall 's--aget extra var)) + ((eq replacer 'elt) + (funcall replacer extra var)) + ((eq replacer 'oref) + (funcall #'slot-value extra (intern var))) + (t + (set-match-data saved-match-data) + (if extra + (funcall replacer var extra) + (funcall replacer var)))))) + (if v (format "%s" v) (signal 's-format-resolve md))) + (set-match-data replacer-match-data)))) template + ;; Need literal to make sure it works + t t) + (set-match-data saved-match-data)))) + +(defvar s-lex-value-as-lisp nil + "If `t' interpolate lisp values as lisp. + +`s-lex-format' inserts values with (format \"%S\").") + +(defun s-lex-fmt|expand (fmt) + "Expand FMT into lisp." + (declare (side-effect-free t)) + (list 's-format fmt (quote 'aget) + (append '(list) + (mapcar + (lambda (matches) + (list + 'cons + (cadr matches) + `(format + (if s-lex-value-as-lisp "%S" "%s") + ,(intern (cadr matches))))) + (s-match-strings-all "${\\([^}]+\\)}" fmt))))) + +(defmacro s-lex-format (format-str) + "`s-format` with the current environment. + +FORMAT-STR may use the `s-format' variable reference to refer to +any variable: + + (let ((x 1)) + (s-lex-format \"x is: ${x}\")) + +The values of the variables are interpolated with \"%s\" unless +the variable `s-lex-value-as-lisp' is `t' and then they are +interpolated with \"%S\"." + (declare (debug (form))) + (s-lex-fmt|expand format-str)) + +(defun s-count-matches (regexp s &optional start end) + "Count occurrences of `regexp' in `s'. + +`start', inclusive, and `end', exclusive, delimit the part of `s' to +match. `start' and `end' are both indexed starting at 1; the initial +character in `s' is index 1. + +This function starts looking for the next match from the end of the +previous match. Hence, it ignores matches that overlap a previously +found match. To count overlapping matches, use +`s-count-matches-all'." + (declare (side-effect-free t)) + (save-match-data + (with-temp-buffer + (insert s) + (goto-char (point-min)) + (count-matches regexp (or start 1) (or end (point-max)))))) + +(defun s-count-matches-all (regexp s &optional start end) + "Count occurrences of `regexp' in `s'. + +`start', inclusive, and `end', exclusive, delimit the part of `s' to +match. `start' and `end' are both indexed starting at 1; the initial +character in `s' is index 1. + +This function starts looking for the next match from the second +character of the previous match. Hence, it counts matches that +overlap a previously found match. To ignore matches that overlap a +previously found match, use `s-count-matches'." + (declare (side-effect-free t)) + (let* ((anchored-regexp (format "^%s" regexp)) + (match-count 0) + (i 0) + (narrowed-s (substring s + (when start (1- start)) + (when end (1- end))))) + (save-match-data + (while (< i (length narrowed-s)) + (when (s-matches? anchored-regexp (substring narrowed-s i)) + (setq match-count (1+ match-count))) + (setq i (1+ i)))) + match-count)) + +(defun s-wrap (s prefix &optional suffix) + "Wrap string S with PREFIX and optionally SUFFIX. + +Return string S with PREFIX prepended. If SUFFIX is present, it +is appended, otherwise PREFIX is used as both prefix and +suffix." + (declare (pure t) (side-effect-free t)) + (concat prefix s (or suffix prefix))) + + +;;; Aliases + +(defalias 's-blank-p 's-blank?) +(defalias 's-blank-str-p 's-blank-str?) +(defalias 's-capitalized-p 's-capitalized?) +(defalias 's-contains-p 's-contains?) +(defalias 's-ends-with-p 's-ends-with?) +(defalias 's-equals-p 's-equals?) +(defalias 's-less-p 's-less?) +(defalias 's-lowercase-p 's-lowercase?) +(defalias 's-matches-p 's-matches?) +(defalias 's-mixedcase-p 's-mixedcase?) +(defalias 's-numeric-p 's-numeric?) +(defalias 's-prefix-p 's-starts-with?) +(defalias 's-prefix? 's-starts-with?) +(defalias 's-present-p 's-present?) +(defalias 's-starts-with-p 's-starts-with?) +(defalias 's-suffix-p 's-ends-with?) +(defalias 's-suffix? 's-ends-with?) +(defalias 's-uppercase-p 's-uppercase?) + + +(provide 's) +;;; s.el ends here diff --git a/elpa/s-20180406.808/s.elc b/elpa/s-20180406.808/s.elc new file mode 100644 index 0000000000000000000000000000000000000000..08d663f479bc78fba79569fff58df1cfd801bf52 GIT binary patch literal 28329 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 arzC)t>?Qezd%b@58UDn9Vv@zy^8W%^e65oJ literal 0 HcmV?d00001 diff --git a/init.el b/init.el index ff57546..c3f4cd2 100644 --- a/init.el +++ b/init.el @@ -26,15 +26,20 @@ There are two things you can do about this warning: ("a24c5b3c12d147da6cef80938dca1223b7c7f70f2f382b26308eba014dc4833a" "a7051d761a713aaf5b893c90eaba27463c791cd75d7257d3a8e66b0c8c346e77" default))) '(package-selected-packages (quote - (json-mode flymake-json tss tide material-theme zenburn-theme ac-js2 auto-complete projectile helm js2-mode cargo rust-mode)))) + (flycheck-rust flycheck json-mode flymake-json tss tide material-theme zenburn-theme ac-js2 auto-complete projectile helm js2-mode cargo rust-mode)))) (custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. ) + +(require 'rust-mode) +(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode)) (setq rust-format-on-save t) (add-hook 'rust-mode-hook 'cargo-minor-mode) +(with-eval-after-load 'rust-mode + (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)) (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode)) (require 'helm-config) (projectile-mode +1)