From 561efc9e0375de6cb529a04dabc47840d3a8011f Mon Sep 17 00:00:00 2001 From: Marcus Kammer <2262664-marcuskammer@user.noreply.gitlab.com> Date: Tue, 14 Apr 2020 10:57:40 +0200 Subject: [PATCH] Install dart-mode && dart-server --- bundle/custom.el | 2 +- .../dart-mode-autoloads.el | 34 + elpa/dart-mode-20190827.2102/dart-mode-pkg.el | 2 + elpa/dart-mode-20190827.2102/dart-mode.el | 625 + elpa/dart-mode-20190827.2102/dart-mode.elc | Bin 0 -> 17191 bytes elpa/dart-mode-readme.txt | 3 + .../dart-server-autoloads.el | 31 + .../dart-server-pkg.el | 2 + elpa/dart-server-20190817.1254/dart-server.el | 1454 ++ .../dart-server-20190817.1254/dart-server.elc | Bin 0 -> 55567 bytes elpa/dart-server-readme.txt | 4 + .../flycheck-autoloads.el | 273 + .../flycheck-buttercup.el | 157 + elpa/flycheck-20200405.2310/flycheck-ert.el | 495 + elpa/flycheck-20200405.2310/flycheck-ert.elc | Bin 0 -> 24583 bytes elpa/flycheck-20200405.2310/flycheck-pkg.el | 16 + elpa/flycheck-20200405.2310/flycheck.el | 11791 ++++++++++++++++ elpa/flycheck-20200405.2310/flycheck.elc | Bin 0 -> 526885 bytes 18 files changed, 14888 insertions(+), 1 deletion(-) create mode 100644 elpa/dart-mode-20190827.2102/dart-mode-autoloads.el create mode 100644 elpa/dart-mode-20190827.2102/dart-mode-pkg.el create mode 100644 elpa/dart-mode-20190827.2102/dart-mode.el create mode 100644 elpa/dart-mode-20190827.2102/dart-mode.elc create mode 100644 elpa/dart-mode-readme.txt create mode 100644 elpa/dart-server-20190817.1254/dart-server-autoloads.el create mode 100644 elpa/dart-server-20190817.1254/dart-server-pkg.el create mode 100644 elpa/dart-server-20190817.1254/dart-server.el create mode 100644 elpa/dart-server-20190817.1254/dart-server.elc create mode 100644 elpa/dart-server-readme.txt create mode 100644 elpa/flycheck-20200405.2310/flycheck-autoloads.el create mode 100644 elpa/flycheck-20200405.2310/flycheck-buttercup.el create mode 100644 elpa/flycheck-20200405.2310/flycheck-ert.el create mode 100644 elpa/flycheck-20200405.2310/flycheck-ert.elc create mode 100644 elpa/flycheck-20200405.2310/flycheck-pkg.el create mode 100644 elpa/flycheck-20200405.2310/flycheck.el create mode 100644 elpa/flycheck-20200405.2310/flycheck.elc diff --git a/bundle/custom.el b/bundle/custom.el index c7741cc0..a98fcc04 100644 --- a/bundle/custom.el +++ b/bundle/custom.el @@ -69,7 +69,7 @@ '(package-enable-at-startup t) '(package-selected-packages (quote - (projectile python-django ivy elpy olivetti ace-window graphviz-dot-mode dot-mode plantuml-mode elisp-format elisp-lint flymake-racket google-translate org-pomodoro elm-mode dashboard pickle poet-theme flymake-eslint json-mode darkroom dockerfile-mode ein spacemacs-theme flucui-themes leuven-theme htmlize scss-mode berrys-theme web-mode python-docstring sphinx-doc sphinx-frontend sphinx-mode ox-nikola racket-mode slime gherkin-mode powershell typescript-mode ob-http ob-ipython ob-restclient nord-theme restclient request restclient-test yaml-mode magit))) + (dart-mode dart-server projectile python-django ivy elpy olivetti ace-window graphviz-dot-mode dot-mode plantuml-mode elisp-format elisp-lint flymake-racket google-translate org-pomodoro elm-mode dashboard pickle poet-theme flymake-eslint json-mode darkroom dockerfile-mode ein spacemacs-theme flucui-themes leuven-theme htmlize scss-mode berrys-theme web-mode python-docstring sphinx-doc sphinx-frontend sphinx-mode ox-nikola racket-mode slime gherkin-mode powershell typescript-mode ob-http ob-ipython ob-restclient nord-theme restclient request restclient-test yaml-mode magit))) '(python-shell-interpreter "python3") '(register-preview-delay 2) '(register-separator 43) diff --git a/elpa/dart-mode-20190827.2102/dart-mode-autoloads.el b/elpa/dart-mode-20190827.2102/dart-mode-autoloads.el new file mode 100644 index 00000000..1e32c6a8 --- /dev/null +++ b/elpa/dart-mode-20190827.2102/dart-mode-autoloads.el @@ -0,0 +1,34 @@ +;;; dart-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "dart-mode" "dart-mode.el" (0 0 0 0)) +;;; Generated autoloads from dart-mode.el + (add-to-list 'auto-mode-alist '("\\.dart\\'" . dart-mode)) + +(autoload 'dart-mode "dart-mode" "\ +Major mode for editing Dart files. + +The hook `dart-mode-hook' is run with no args at mode +initialization. + +Key bindings: +\\{dart-mode-map} + +\(fn)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dart-mode" '("dart-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; dart-mode-autoloads.el ends here diff --git a/elpa/dart-mode-20190827.2102/dart-mode-pkg.el b/elpa/dart-mode-20190827.2102/dart-mode-pkg.el new file mode 100644 index 00000000..3a022fbb --- /dev/null +++ b/elpa/dart-mode-20190827.2102/dart-mode-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "dart-mode" "20190827.2102" "Major mode for editing Dart files" '((emacs "24.3")) :commit "04fcd649f19d49390079fbf2920a10bf37f6a634" :keywords '("languages") :authors '(("Brady Trainor" . "mail@bradyt.net")) :maintainer '("Brady Trainor" . "mail@bradyt.net") :url "https://github.com/bradyt/dart-mode") diff --git a/elpa/dart-mode-20190827.2102/dart-mode.el b/elpa/dart-mode-20190827.2102/dart-mode.el new file mode 100644 index 00000000..f4284a17 --- /dev/null +++ b/elpa/dart-mode-20190827.2102/dart-mode.el @@ -0,0 +1,625 @@ +;;; dart-mode.el --- Major mode for editing Dart files -*- lexical-binding: t; -*- + +;; Author: Brady Trainor +;; URL: https://github.com/bradyt/dart-mode +;; Package-Version: 20190827.2102 +;; Version: 1.0.4 +;; Package-Requires: ((emacs "24.3")) +;; Keywords: languages + +;;; Commentary: + +;; Major mode for editing Dart files. + +;; Provides basic syntax highlighting and indentation. + +;;; Code: + +;;; Configuration + +(defvar dart-mode-map (make-sparse-keymap) + "Keymap used in dart-mode buffers.") +(define-key dart-mode-map (kbd "") 'dart-dedent-simple) +(define-key dart-mode-map (kbd "C-c C-i") 'indent-according-to-mode) + + +;;; Indentation + +(defcustom dart-indent-trigger-commands + '(indent-for-tab-command yas-expand yas/expand dart-dedent-simple) + "Commands that might trigger a `dart-indent-line' call." + :type '(repeat symbol) + :group 'dart) + +(defun dart-indent-line-function () + "`indent-line-function' for Dart mode. +When the variable `last-command' is equal to one of the symbols +inside `dart-indent-trigger-commands' it cycles possible +indentation levels from right to left." + (if (and (memq this-command dart-indent-trigger-commands) + (eq last-command this-command)) + (dart-indent-simple) + (dart-indent-line-relative))) + +(defun dart-indent-simple (&optional backwards) + (interactive) + (save-excursion + (indent-line-to + (max 0 (indent-next-tab-stop (current-indentation) backwards)))) + (when (< (current-column) (current-indentation)) + (back-to-indentation))) + +(defun dart-dedent-simple () + (interactive) + (dart-indent-simple 'backwards)) + +(defun dart-depth-of-line () + (save-excursion + (back-to-indentation) + (let ((depth (car (syntax-ppss)))) + (when (and (char-after) + (= (char-syntax (char-after)) ?\))) + (while (and (char-after) + (/= (char-syntax (char-after)) ?\() + (/= (char-after) ?\C-j)) + (when (= (char-syntax (char-after)) ?\)) + (setq depth (1- depth))) + (forward-char))) + depth))) + +(defun dart-indent-line-relative () + (let ((curr-depth (dart-depth-of-line)) + prev-line + prev-depth + prev-indent) + (save-excursion + (beginning-of-line) + (catch 'done + (while t + (when (= (point) 1) + (throw 'done t)) + (forward-line -1) + (unless (looking-at (rx (and bol (zero-or-more space) eol))) + (setq prev-line t) + (setq prev-indent (current-indentation)) + (setq prev-depth (dart-depth-of-line)) + (throw 'done t))))) + (save-excursion + (if prev-line + (indent-line-to (max 0 (+ prev-indent + (* (- curr-depth prev-depth) + tab-width)))) + (indent-line-to 0))) + (when (< (current-column) (current-indentation)) + (back-to-indentation)))) + + +;;; Fontification + +(defvar dart--file-directives + '("as" "deferred" "export" "hide" "import" "library" "of" "part" + "show")) + +(defvar dart--builtins + ;; ECMA 408; Section: Identifier Reference + ;; "Built-in identifiers" + '("abstract" "as" "covariant" "deferred" "dynamic" "export" + "external" "factory" "Function" "get" "implements" "import" + "interface" "library" "mixin" "operator" "part" "set" "static" + "typedef")) + +(defvar dart--keywords + ;; ECMA 408; Section: Reserved Words + '("assert" "break" "case" "catch" "class" "const" "continue" + "default" "do" "else" "enum" "extends" "final" "finally" "for" + "if" "in" "is" "new" "rethrow" "return" "super" "switch" "this" + "throw" "try" "var" "while" "with")) + +(defvar dart--types '("bool" "double" "int" "num" "void")) + +(defvar dart--constants '("false" "null" "true")) + +(defvar dart--async-keywords-re (rx word-start + (or "async" "await" "sync" "yield") + word-end + (zero-or-one ?*))) + +(defvar dart--number-re (rx symbol-start + (zero-or-one ?-) + (group (or (and (one-or-more digit) + (zero-or-one + (and ?. (one-or-more digit)))) + (and ?. (one-or-more digit))) + (zero-or-one (and (or ?e ?E) + (zero-or-one (or ?+ ?-)) + (one-or-more digit)))))) + +(defvar dart--hex-number-re (rx symbol-start + (zero-or-one ?-) + (group (or "0x" "0X") + (one-or-more (any (?a . ?f) + (?A . ?F) + digit))))) + +(defvar dart--operator-declaration-re (rx "operator" + (one-or-more space) + (group + (one-or-more (not (any ?\()))))) + +(eval-and-compile (defun dart--identifier (&optional case) + `(and (or word-start symbol-start) + (zero-or-more (any ?$ ?_)) + ,(if case + case + 'alpha) + (zero-or-more (or ?$ ?_ alnum))))) + +(defvar dart--metadata-re (rx ?@ (eval (dart--identifier)))) + +(defvar dart--types-re (rx (eval (dart--identifier 'upper)))) + +(defvar dart--constants-re (rx (and word-start + upper + (>= 2 (or upper ?_)) + word-end))) + +(defun dart--string-interpolation-id-func (limit) + "Font-lock matcher for string interpolation identifiers. + +These have the form $variableName. + +Can fontify entire match with group 0, or using group 1 for sigil, +group 2 for variableName." + (catch 'result + (let (data end syntax) + (while (re-search-forward (rx (group ?$) + (group (zero-or-more ?_) + lower + (zero-or-more (or ?_ alnum)))) + limit t) + (setq data (match-data)) + (setq end (match-end 2)) + (setq syntax (syntax-ppss)) + ;; Check that we are in a string and not in a raw string + (when (and (nth 3 syntax) + (or (= (nth 8 syntax) 1) + (not (eq (char-before (nth 8 syntax)) ?r)))) + (set-match-data data) + (goto-char end) + (throw 'result t)) + (when end + (goto-char end))) + (throw 'result nil)))) + +(defun dart--string-interpolation-exp-func (limit) + "Font-lock matcher for string interpolation expressions. + +These have the form ${expression}. + +Can fontify entire match with group 0, or using group 1 for sigil, +groups 2 and 4 for curly brackets, and 3 for contents." + (catch 'result + (let (sigil beg open close end depth) + ;; Loop and put point after ${ + (while (and (search-forward "${" limit t) + ;; Check that we are in a string and not in a raw string + (save-excursion + (and (nth 3 (syntax-ppss)) + (not (eq (char-before (nth 8 (syntax-ppss))) ?r))))) + ;; "a string with ${someInterpolation + aValue} inside of it." + ;; ^^^ ^^ + ;; ||| || + ;; sigil -+|+- open close -++- end + ;; +- beg + (setq open (point)) + (setq beg (- open 1)) + (setq sigil (- open 2)) + (setq depth 1) + ;; Move forward until limit, while depth is positive and we + ;; are inside string. + (while (and (> depth 0) + (< (point) limit) + (nth 3 (syntax-ppss))) + (setq depth (+ depth (pcase (char-after) + (?\{ 1) + (?\} -1) + (_ 0)))) + (forward-char)) + (setq end (point)) + ;; If depth is zero, we have found a closing } within string + ;; and before limit. Set `match-data', `point', and return `t'. + (when (= depth 0) + (setq close (1- end)) + (set-match-data (list sigil end + sigil beg + beg open + open close + close end)) + (goto-char end) + (throw 'result t)) + ;; If the candidate did not meet criteria, put point at end + ;; and search again. + (goto-char end)) + ;; When there are no more candidate "${", return nil. + (throw 'result nil)))) + +(defun dart--function-declaration-func (limit) + "Font-lock matcher function for function declarations. + +Matches function declarations before LIMIT that look like, + + \"lowercaseIdentifier([...]) [[a]sync[*], {, =>]\" + +For example, \"main\" in \"void main() async\" would be matched." + (catch 'result + (let (beg end) + (while (re-search-forward + (rx (group (eval (dart--identifier 'lower))) ?\() limit t) + (setq beg (match-beginning 1)) + (setq end (match-end 1)) + (condition-case nil + (progn + (up-list) + (when (looking-at (rx (one-or-more space) + (or "async" "async*" "sync*" "{" "=>"))) + (set-match-data (list beg end)) + (goto-char end) + (throw 'result t))) + (scan-error nil)) + (goto-char end)) + (throw 'result nil)))) + +(defun dart--abstract-method-func (limit) + "Font-lock matcher function for abstract methods. + +Matches function declarations before LIMIT that look like, + + \" [^ ][^=]* lowercaseIdentifier([...]);\" + +For example, \"compareTo\" in \" int compareTo(num other);\" would be +matched." + (catch 'result + (let (beg end) + (while (re-search-forward + (rx (and (not (any ?\.)) (group (eval (dart--identifier 'lower)))) ?\() limit t) + (setq beg (match-beginning 1)) + (setq end (match-end 1)) + (condition-case nil + (progn + (up-list) + (when (and (< (point) (point-max)) + (= (char-after (point)) ?\;)) + (goto-char beg) + (back-to-indentation) + (when (and (= (current-column) 2) + (not (looking-at "return")) + (string-match-p + " " (buffer-substring-no-properties + (point) beg)) + (not (string-match-p + "=" (buffer-substring-no-properties + (point) beg)))) + (goto-char end) + (set-match-data (list beg end)) + (throw 'result t)))) + (scan-error nil)) + (goto-char end))) + (throw 'result nil))) + +(defun dart--declared-identifier-func (limit) + "Font-lock matcher function for declared identifiers. + +Matches declared identifiers before LIMIT that look like, + + \"finalConstVarOrType lowercaseIdentifier\" + +For example, \"height\" in \"const int height\" would be matched." + (catch 'result + (let (beg end) + (while (re-search-forward + (rx + (and (group (or (or "const" "final" + "bool" "double" "dynamic" "int" "num" "void" + "var" + "get" "set") + (eval (dart--identifier 'upper))) + (zero-or-more ?>)) + (one-or-more (or space ?\C-j)) + (group (eval (dart--identifier 'lower))) + (not (any ?\( alnum ?$ ?_)))) + limit t) + (setq beg (match-beginning 2)) + (setq end (match-end 2)) + ;; Check for false positives + (when (not (member (match-string 2) + '("bool" "double" "dynamic" "int" "num" "void" + "var" + "get" "set"))) + (goto-char end) + (unless (nth 3 (syntax-ppss)) + (set-match-data (list beg end)) + (throw 'result t))) + (goto-char (match-end 1))) + (throw 'result nil)))) + +(defun dart--in-parenthesized-expression-or-formal-parameter-list-p () + "Returns `t' if `point' is in parentheses, otherwise `nil'. + +In particular, parenthesized expressions or formal parameter lists." + (save-excursion + (catch 'result + ;; Attempt to jump out of parentheses. + (condition-case nil + (backward-up-list) + (scan-error (throw 'result nil))) + ;; If we've only jumped out of optional or named section of + ;; formal parameters, try to jump again. + (when (member (char-after (point)) '(?\[ ?\{)) + (condition-case nil + (backward-up-list) + (scan-error (throw 'result nil)))) + (throw 'result (= (char-after (point)) ?\())))) + +(defun dart--declared-identifier-anchor-func (limit) + "Font-lock matcher for declared identifier. + +Uses `dart--declared-identifier-func' to find candidates before +LIMIT, and checks that they are not in parentheses. + +This matcher is an anchor to match multiple identifiers in a +single variable declaration. From ECMA-408, + + variableDeclaration: + declaredIdentifier (', ' identifier)* + ; + +After this function sets anchor, font-lock will use the function +`dart--declared-identifier-next-func' to find subsequent +identifiers." + (catch 'result + (let (data) + (while (dart--declared-identifier-func limit) + (setq data (match-data)) + (unless (dart--in-parenthesized-expression-or-formal-parameter-list-p) + (set-match-data data) + (goto-char (match-end 0)) + (throw 'result t)) + (goto-char (match-end 0))) + (throw 'result nil)))) + +(defun dart--declared-identifier-next-func (limit) + "Font-lock matcher for subsequent identifiers. + +For use after `dart--declared-identifier-anchor-func' sets +anchor, this function will look for subsequent identifers to +fontify as declared variables. From ECMA-408, + + variableDeclaration: + declaredIdentifier (', ' identifier)* + ;" + (catch 'result + (let ((depth (car (syntax-ppss)))) + (while t + (cond + ;; If point is followed by semi-colon, we are done. + ((or (> (point) limit) + (= (char-after (point)) ?\;) + (< (car (syntax-ppss)) depth)) + (throw 'result nil)) + ;; If point is followed by comma, and we are still at same + ;; depth, then attempt to match another identifier, otherwise + ;; return nil. + ((and (= (char-after (point)) ?\x2c) ; ?, + (= (car (syntax-ppss)) depth)) + (if (looking-at (rx ?\x2c + (one-or-more space) + (group (eval (dart--identifier 'lower))))) + (progn (set-match-data (list (match-beginning 1) + (match-end 1))) + (goto-char (match-end 0)) + (throw 'result t)) + (throw 'result nil))) + ;; Otherwise, if we are still before `point-max' (shouldn't + ;; this be `limit'? May be a bad attempt to deal with + ;; multiline searches. Should research how this is done with + ;; font-lock.), move forward. + ((< (point) (point-max)) + (forward-char)) + ;; Otherwise, return nil. + (t (throw 'result nil))))))) + +(defun dart--anonymous-function-matcher (limit) + "Font-lock matcher for start of anonymous functions. + +Looks for opening parenthesis, tries to jump to opening +parenthesis, ensure it is not preceded by for, while, etc. Then +tries to jump to closing parenthesis and check if followed by \" +{\" or \" =>\". + +Used with `dart--untyped-parameter-anchored-matcher' to fontify +untyped parameters. For example, in + + (untypedParameter) => untypedParameter.length" + (catch 'result + (let (beg end) + (while (search-forward "(" limit t) + (setq beg (match-beginning 0)) + (setq end (match-end 0)) + (unless (looking-back (rx (or (and (or "do" "for" "if" "switch" "while") + space) + "super") + ?\() + (point-at-bol)) + (condition-case nil + (up-list) + (scan-error (throw 'result nil))) + (when (looking-at (rx space (or ?\{ "=>"))) + (set-match-data (list beg end)) + (goto-char end) + (throw 'result t)) + (goto-char end))) + (throw 'result nil)))) + +(defun dart--untyped-parameter-anchored-matcher (limit) + "Font-lock anchored-matcher for untyped parameters. + +Searches forward for for lowercase idenitifer and ensures depth +is still same. + +Used with `dart--anonymous-function-matcher' to fontify +untyped parameters. For example, in + + (untypedParameter) => untypedParameter.length" + (let (beg end) + (catch 'result + (if (equal (char-after) ?\)) + (throw 'result nil)) + (let ((depth (car (syntax-ppss)))) + (while (re-search-forward + (rx (and (group (or (one-or-more (char ?_)) + (eval (dart--identifier 'lower)))) + (or ?, ?\))))) + (setq beg (match-beginning 1)) + (setq end (match-end 1)) + (goto-char end) + (if (or (> (point) limit) + (< (car (syntax-ppss)) depth)) + (throw 'result nil) + (set-match-data (list beg end)) + (throw 'result t)))) + (throw 'result nil)))) + +(defun dart--get-point-at-end-of-list () + (let (pt) + (save-excursion + (up-list) + (setq pt (point))) + pt)) + +(defvar dart-font-lock-defaults + '((dart-font-lock-keywords-1 dart-font-lock-keywords-1 + dart-font-lock-keywords-2 + dart-font-lock-keywords-3))) + +(defvar dart-font-lock-keywords-1 + `((,(regexp-opt dart--file-directives 'words) . font-lock-builtin-face) + (dart--function-declaration-func . font-lock-function-name-face) + (,dart--operator-declaration-re . (1 font-lock-function-name-face)) + (dart--abstract-method-func . font-lock-function-name-face))) + +(defvar dart-font-lock-keywords-2 + `(,dart--async-keywords-re + ,(regexp-opt dart--keywords 'words) + (,(regexp-opt dart--builtins 'words) . font-lock-builtin-face) + (,(regexp-opt dart--constants 'words) . font-lock-constant-face) + (,dart--hex-number-re . (1 font-lock-constant-face)) + (,dart--number-re . (1 font-lock-constant-face)) + (,dart--metadata-re . font-lock-constant-face) + (,dart--constants-re . font-lock-constant-face) + (,(regexp-opt dart--types 'words) . font-lock-type-face) + (,dart--types-re . font-lock-type-face) + (dart--function-declaration-func . font-lock-function-name-face) + (,dart--operator-declaration-re . (1 font-lock-function-name-face)) + (dart--abstract-method-func . font-lock-function-name-face))) + +(defvar dart-font-lock-keywords-3 + (append + dart-font-lock-keywords-2 + `((dart--declared-identifier-func . font-lock-variable-name-face) + (dart--declared-identifier-anchor-func + . (dart--declared-identifier-next-func + nil + nil + (0 font-lock-variable-name-face))) + (dart--anonymous-function-matcher + . (dart--untyped-parameter-anchored-matcher + (dart--get-point-at-end-of-list) + nil + (0 font-lock-variable-name-face))) + (dart--string-interpolation-id-func (0 font-lock-variable-name-face t)) + (dart--string-interpolation-exp-func (0 font-lock-variable-name-face t))))) + +(defun dart-syntax-propertize-function (beg end) + "Sets syntax-table text properties for raw and/or multiline strings. + +We use fences uniformly for consistency. + +In raw strings, we modify backslash characters to have punctuation +syntax rather than escape syntax. + +String interpolation is not handled correctly yet, but the fixes to +quote characters in multiline strings, and escape characters in raw +strings, ensures that code outside of strings is not highlighted as +strings." + (goto-char beg) + ;; We rely on syntax-propertize-extend-region-functions that `beg` + ;; will be at beginning of line, but we ensure here that we are not + ;; in a string + (while (nth 3 (syntax-ppss)) + (goto-char (nth 8 (syntax-ppss))) + (beginning-of-line)) + ;; Search for string opening + (while (re-search-forward (rx (group (optional ?r)) + (group (or (repeat 3 ?\") + (repeat 3 ?\') + ?\" + ?\'))) + end t) + (let ((bos (match-beginning 2)) + (rawp (equal (match-string-no-properties 1) "r")) + (string-delimiter (match-string-no-properties 2))) + ;; Set string fence syntax at beginning of string + (put-text-property bos (1+ bos) 'syntax-table (string-to-syntax "|") nil) + ;; Look for the end of string delimiter, depending on rawp and + ;; string-delimiter + ;; Unless rawp, ensure an even number of backslashes + (when (or (looking-at (concat (unless rawp (rx (zero-or-more ?\\ ?\\))) + string-delimiter)) + (re-search-forward (concat (unless rawp (rx (not (any ?\\)) (zero-or-more ?\\ ?\\))) + string-delimiter) + end t)) + (let ((eos (match-end 0))) + ;; Set end of string fence delimiter + (put-text-property (1- eos) eos 'syntax-table (string-to-syntax "|") nil) + ;; For all strings, remove fence property between fences + ;; For raw strings, set all backslashes to punctuation syntax + (dolist (pt (number-sequence (1+ bos) (- eos 2))) + (when (equal (get-text-property pt 'syntax-table) (string-to-syntax "|")) + (remove-text-properties pt (1+ pt) 'syntax-table)) + (when (and rawp (equal (char-after pt) ?\\)) + (put-text-property pt (1+ pt) 'syntax-table (string-to-syntax ".") nil))) + (goto-char eos)))))) + + +;;; Initialization + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.dart\\'" . dart-mode)) + +;;;###autoload +(define-derived-mode dart-mode prog-mode "Dart" + "Major mode for editing Dart files. + +The hook `dart-mode-hook' is run with no args at mode +initialization. + +Key bindings: +\\{dart-mode-map}" + (modify-syntax-entry ?/ "_ 124b") + (modify-syntax-entry ?* ". 23") + (modify-syntax-entry ?\n "> b") + (modify-syntax-entry ?\' "\"") + (modify-syntax-entry ?\> ".") + (modify-syntax-entry ?\< ".") + (setq-local electric-indent-chars '(?\n ?\) ?\] ?\})) + (setq-local comment-start "//") + (setq-local comment-end "") + (setq fill-column 80) + (setq font-lock-defaults dart-font-lock-defaults) + (setq-local indent-line-function 'dart-indent-line-function) + (setq indent-tabs-mode nil) + (setq tab-width 2) + (setq-local syntax-propertize-function 'dart-syntax-propertize-function)) + +(provide 'dart-mode) + +;;; dart-mode.el ends here diff --git a/elpa/dart-mode-20190827.2102/dart-mode.elc b/elpa/dart-mode-20190827.2102/dart-mode.elc new file mode 100644 index 0000000000000000000000000000000000000000..22c4e6e8583ee208529c95218a4ed364a5813038 GIT binary patch literal 17191 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 Ux48L?**-(Yg1Mhg;%hhl8`G=D*#H0l literal 0 HcmV?d00001 diff --git a/elpa/dart-mode-readme.txt b/elpa/dart-mode-readme.txt new file mode 100644 index 00000000..4d77bdfa --- /dev/null +++ b/elpa/dart-mode-readme.txt @@ -0,0 +1,3 @@ +Major mode for editing Dart files. + +Provides basic syntax highlighting and indentation. diff --git a/elpa/dart-server-20190817.1254/dart-server-autoloads.el b/elpa/dart-server-20190817.1254/dart-server-autoloads.el new file mode 100644 index 00000000..89c12e59 --- /dev/null +++ b/elpa/dart-server-20190817.1254/dart-server-autoloads.el @@ -0,0 +1,31 @@ +;;; dart-server-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "dart-server" "dart-server.el" (0 0 0 0)) +;;; Generated autoloads from dart-server.el + +(autoload 'dart-server "dart-server" "\ +Toggle Dart-Server mode on or off. +With a prefix argument ARG, enable Dart-Server mode if ARG is +positive, and disable it otherwise. If called from Lisp, enable +the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'. +\\{dart-server-map} + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dart-server" '("dart-server-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; dart-server-autoloads.el ends here diff --git a/elpa/dart-server-20190817.1254/dart-server-pkg.el b/elpa/dart-server-20190817.1254/dart-server-pkg.el new file mode 100644 index 00000000..148679b1 --- /dev/null +++ b/elpa/dart-server-20190817.1254/dart-server-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "dart-server" "20190817.1254" "Minor mode for editing Dart files" '((emacs "24.5") (cl-lib "0.5") (dash "2.10.0") (flycheck "0.23") (s "1.10")) :commit "aba838e8ee2f30309f366e8a91c17616549003ce" :keywords '("languages") :authors '(("Natalie Weizenbaum") ("Brady Trainor" . "mail@bradyt.com")) :maintainer '("Brady Trainor" . "mail@bradyt.com") :url "https://github.com/bradyt/dart-server") diff --git a/elpa/dart-server-20190817.1254/dart-server.el b/elpa/dart-server-20190817.1254/dart-server.el new file mode 100644 index 00000000..55a35398 --- /dev/null +++ b/elpa/dart-server-20190817.1254/dart-server.el @@ -0,0 +1,1454 @@ +;;; dart-server.el --- Minor mode for editing Dart files -*- lexical-binding: t; -*- + +;; Author: Natalie Weizenbaum +;; Brady Trainor +;; Maintainer: Brady Trainor +;; URL: https://github.com/bradyt/dart-server +;; Package-Version: 20190817.1254 +;; Version: 0.1.0 +;; Package-Requires: ((emacs "24.5") (cl-lib "0.5") (dash "2.10.0") (flycheck "0.23") (s "1.10")) +;; Keywords: languages + +;; Copyright (C) 2011 Google Inc. +;; +;; 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 . + +;; This file contains several functions and variables adapted from the +;; code in https://github.com/dominikh/go-mode.el + +;; Definitions adapted from go-mode.el are +;; +;; gofmt-command gofmt-args gofmt-show-errors gofmt go--apply-rcs-patch +;; gofmt--kill-error-buffer gofmt--process-errors gofmt-before-save +;; go--goto-line go--delete-whole-line + +;; go-mode.el uses this license: +;; +;; Copyright (c) 2014 The go-mode Authors. All rights reserved. +;; +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions are +;; met: +;; +;; * Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; * Redistributions in binary form must reproduce the above +;; copyright notice, this list of conditions and the following disclaimer +;; in the documentation and/or other materials provided with the +;; distribution. +;; * Neither the name of the copyright holder nor the names of its +;; contributors may be used to endorse or promote products derived from +;; this software without specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; Commentary: + +;; Minor mode for editing Dart files. + +;; Provides dart server features, such as formatting, analysis, +;; flycheck, etc. + +;;; Code: + +(require 'cl-lib) +(require 'compile) +(require 'dash) +(ignore-errors + (require 'flycheck)) +(require 'help-mode) +(require 'json) +(require 'rx) +(require 's) +(require 'subr-x) + +;;; Utility functions and macros + +(defun dart-server-beginning-of-statement () + "Moves to the beginning of a Dart statement. + +Unlike `c-beginning-of-statement', this handles maps correctly +and will move to the top level of a bracketed statement." + (while + (progn + (back-to-indentation) + (while (eq (char-after) ?}) + (forward-char) + (forward-sexp -1) + (back-to-indentation)) + (unless (dart-server--beginning-of-statement-p)) (forward-line -1)))) + +(defun dart-server--beginning-of-statement-p () + "Returns whether the point is at the beginning of a statement. + +Statements are assumed to begin on their own lines. This returns +true for positions before the start of the statement, but on its line." + (and + (save-excursion + (skip-syntax-forward " ") + (not (or (bolp) (eq (char-after) ?})))) + (save-excursion + (skip-syntax-backward " ") + (when (bolp) + (cl-loop do (forward-char -1) + while (looking-at "^ *$")) + (skip-syntax-backward " ") + (cl-case (char-before) + ((?} ?\;) t)))))) + +(defun dart-server--delete-whole-line (&optional arg) + "Delete the current line without putting it in the `kill-ring'. +Derived from function `kill-whole-line'. ARG is defined as for that +function." + (setq arg (or arg 1)) + (if (and (> arg 0) + (eobp) + (save-excursion (forward-visible-line 0) (eobp))) + (signal 'end-of-buffer nil)) + (if (and (< arg 0) + (bobp) + (save-excursion (end-of-visible-line) (bobp))) + (signal 'beginning-of-buffer nil)) + (cond ((zerop arg) + (delete-region (progn (forward-visible-line 0) (point)) + (progn (end-of-visible-line) (point)))) + ((< arg 0) + (delete-region (progn (end-of-visible-line) (point)) + (progn (forward-visible-line (1+ arg)) + (unless (bobp) + (backward-char)) + (point)))) + (t + (delete-region (progn (forward-visible-line 0) (point)) + (progn (forward-visible-line arg) (point)))))) + +(defconst dart-server--identifier-re + "[a-zA-Z_$][a-zA-Z0-9_$]*" + "A regular expression that matches keywords.") + +(defun dart-server--forward-identifier () + "Moves the point forward through a Dart identifier." + (when (looking-at dart-server--identifier-re) + (goto-char (match-end 0)))) + +(defun dart-server--kill-buffer-and-window (buffer) + "Kills BUFFER, and its window if it has one. + +This is different than `kill-buffer' because, if the buffer has a +window, it respects the `quit-restore' window parameter. See +`quit-window' for details." + (-if-let (window (get-buffer-window buffer)) + (quit-window t window) + (kill-buffer buffer))) + +(defun dart-server--get (alist &rest keys) + "Recursively calls `cdr' and `assoc' on ALIST with KEYS. +Returns the value rather than the full alist cell." + (--reduce-from (cdr (assoc it acc)) alist keys)) + +(defmacro dart-server--json-let (json fields &rest body) + "Assigns variables named FIELDS to the corresponding fields in JSON. +FIELDS may be either identifiers or (ELISP-IDENTIFIER JSON-IDENTIFIER) pairs." + (declare (indent 2)) + (let ((json-value (make-symbol "json"))) + `(let ((,json-value ,json)) + (let ,(--map (if (symbolp it) + `(,it (dart-server--get ,json-value ',it)) + (-let [(variable key) it] + `(,variable (dart-server--get ,json-value ',key)))) + fields) + ,@body)))) + +(defun dart-server--property-string (text prop value) + "Returns a copy of TEXT with PROP set to VALUE. + +Converts TEXT to a string if it's not already." + (let ((copy (substring (format "%s" text) 0))) + (put-text-property 0 (length copy) prop value copy) + copy)) + +(defun dart-server--face-string (text face) + "Returns a copy of TEXT with its font face set to FACE. + +Converts TEXT to a string if it's not already." + (dart-server--property-string text 'face face)) + +(defmacro dart-server--fontify-excursion (face &rest body) + "Applies FACE to the region moved over by BODY." + (declare (indent 1)) + (-let [start (make-symbol "start")] + `(-let [,start (point)] + ,@body + (put-text-property ,start (point) 'face ,face)))) + +(defun dart-server--flash-highlight (offset length) + "Briefly highlights the text defined by OFFSET and LENGTH. +OFFSET and LENGTH are expected to come from the analysis server, +rather than Elisp." + (-let [overlay (make-overlay (+ 1 offset) (+ 1 offset length))] + (overlay-put overlay 'face 'highlight) + (run-at-time "1 sec" nil (lambda () (delete-overlay overlay))))) + +(defun dart-server--read-file (filename) + "Returns the contents of FILENAME." + (with-temp-buffer + (insert-file-contents filename) + (buffer-string))) + +(defmacro dart-server--with-temp-file (name-variable &rest body) + "Creates a temporary file for the duration of BODY. +Assigns the filename to NAME-VARIABLE. Doesn't change the current buffer. +Returns the value of the last form in BODY." + (declare (indent 1)) + `(-let [,name-variable (make-temp-file "dart-server.")] + (unwind-protect + (progn ,@body) + (delete-file ,name-variable)))) + +(defun dart-server--run-process (executable &rest args) + "Runs EXECUTABLE with ARGS synchronously. +Returns (STDOUT STDERR EXIT-CODE)." + (dart-server--with-temp-file stderr-file + (with-temp-buffer + (-let [exit-code + (apply #'call-process + executable nil (list t stderr-file) nil args)] + (list + (buffer-string) + (dart-server--read-file stderr-file) + exit-code))))) + +(defun dart-server--try-process (executable &rest args) + "Like `dart-server--run-process', but only returns stdout. +Any stderr is logged using dart-server-log. Returns nil if the exit code is non-0." + (-let [result (apply #'dart-server--run-process executable args)] + (unless (string-empty-p (nth 1 result)) + (dart-server-log (format "Error running %S:\n%s" (cons executable args) (nth 1 result)))) + (if (eq (nth 2 result) 0) (nth 0 result)))) + +(defvar dart-server--do-it-again-callback nil + "A callback to call when `dart-server-do-it-again' is invoked. + +Only set in `dart-server-popup-mode'.") +(make-variable-buffer-local 'dart-server--do-it-again-callback) + + +;;; General configuration + +(defcustom dart-server-sdk-path + ;; Use Platform.resolvedExecutable so that this logic works through symlinks + ;; and wrapper scripts. + (-when-let (dart (or (executable-find "dart") + (let ((flutter (executable-find "flutter"))) + (when flutter + (expand-file-name "cache/dart-sdk/bin/dart" + (file-name-directory flutter)))))) + (dart-server--with-temp-file input + (with-temp-file input (insert " + import 'dart:io'; + + void main() { + print(Platform.resolvedExecutable); + } + ")) + (-when-let (result (dart-server--try-process dart input)) + (file-name-directory + (directory-file-name + (file-name-directory (string-trim result))))))) + "The absolute path to the root of the Dart SDK." + :group 'dart-server + :type 'directory + :package-version '(dart-server . "0.1.0")) + +(defun dart-server-executable-path () + "The absolute path to the 'dart' executable. + +Returns nil if `dart-server-sdk-path' is nil." + (when dart-server-sdk-path + (concat dart-server-sdk-path + (file-name-as-directory "bin") + (if (memq system-type '(ms-dos windows-nt)) + "dart.exe" + "dart")))) + + +;;; Configuration + +(defvar dart-server-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c ?") 'dart-server-show-hover) + ;; (define-key map (kbd "C-c C-g") 'dart-server-goto) + (define-key map (kbd "C-c C-f") 'dart-server-find-refs) + (define-key map (kbd "C-c C-e") 'dart-server-find-member-decls) + (define-key map (kbd "C-c C-r") 'dart-server-find-member-refs) + (define-key map (kbd "C-c C-t") 'dart-server-find-top-level-decls) + (define-key map (kbd "C-c C-o") 'dart-server-format) + (define-key map (kbd "M-/") 'dart-server-expand) + (define-key map (kbd "M-?") 'dart-server-expand-parameters) + map) + "Keymap used in dart-server buffers.") + + +;;; Dart analysis server + +(cl-defstruct + (dart-server--analysis-server + (:constructor dart-server--make-analysis-server)) + "Struct containing data for an instance of a Dart analysis server. + +The slots are: +- `process': the process of the running server. +- `buffer': the buffer where responses from the server are written." + process buffer) + +(defgroup dart-server nil + "Major mode for editing Dart code." + :group 'languages) + +(defvar dart-server-debug nil + "If non-nil, enables writing debug messages for dart-server.") + +(defcustom dart-server-enable-analysis-server nil + "If non-nil, enables support for Dart analysis server. + +The Dart analysis server adds support for error checking, code completion, +navigation, and more." + :group 'dart-server + :type 'boolean + :package-version '(dart-server . "0.1.0")) + +(defvar dart-server--analysis-server nil + "The instance of the Dart analysis server we are communicating with.") + +(defun dart-server--analysis-server-snapshot-path () + "The absolute path to the snapshot file that runs the Dart analysis server." + (when dart-server-sdk-path + (concat dart-server-sdk-path + (file-name-as-directory "bin") + (file-name-as-directory "snapshots") + "analysis_server.dart.snapshot"))) + +(defvar dart-server-analysis-roots nil + "The list of analysis roots that are known to the analysis server. + +All Dart files underneath the analysis roots are analyzed by the analysis +server.") + +(defvar dart-server--analysis-server-next-id 0 + "The ID to use for the next request to the Dart analysis server.") + +(defvar dart-server--analysis-server-callbacks nil + "An alist of ID to callback to be called when the analysis server responds. + +Each request to the analysis server has an associated ID. When the analysis +server sends a response to a request, it tags the response with the ID of the +request. We look up the callback for the request in this alist and run it with +the JSON decoded server response.") + +(defvar dart-server--analysis-server-subscriptions nil + "An alist of event names to lists of callbacks to be called for those events. + +These callbacks take the event object and an opaque subcription +object which can be passed to `dart-server--analysis-server-unsubscribe'.") + +(defun dart-server-info (msg) + "Logs MSG to the dart log if `dart-server-debug' is non-nil." + (when dart-server-debug (dart-server-log msg))) + +(defun dart-server-log (msg) + "Logs MSG to the dart log." + (let* ((log-buffer (get-buffer-create "*dart-server-debug*")) + (iso-format-string "%Y-%m-%dT%T%z") + (timestamp-and-log-string + (format-time-string iso-format-string (current-time)))) + (with-current-buffer log-buffer + (goto-char (point-max)) + (insert "\n\n\n") + (insert (concat timestamp-and-log-string + "\n" + msg)) + (insert "\n")))) + +(defun dart-server--normalize-path (path) + (if (equal system-type 'windows-nt) + (replace-regexp-in-string (rx "/") (rx "\\") path) + path)) + +(defun dart-server--start-analysis-server-for-current-buffer () + "Initialize Dart analysis server for current buffer. + +This starts Dart analysis server and adds either the pub root +directory or the current file directory to the analysis roots." + (unless dart-server--analysis-server (dart-server-start-analysis-server)) + ;; TODO(hterkelsen): Add this file to the priority files. + (dart-server-add-analysis-root-for-file) + (add-hook 'first-change-hook #'dart-server-add-analysis-overlay t t) + (add-hook 'after-change-functions #'dart-server-change-analysis-overlay t t) + (add-hook 'after-save-hook #'dart-server-remove-analysis-overlay t t) + (when (boundp 'flycheck-checkers) + (add-to-list 'flycheck-checkers 'dart-server-analysis-server))) + +(defun dart-server-start-analysis-server () + "Start the Dart analysis server. + +Initializes analysis server support for all `dart-server' buffers." + (when dart-server--analysis-server + (-let [process (dart-server--analysis-server-process dart-server--analysis-server)] + (when (process-live-p process) (kill-process process))) + (kill-buffer (dart-server--analysis-server-buffer dart-server--analysis-server))) + + (let* ((process-connection-type nil) + (dart-server-process + (start-process "dart-server-analysis-server" + "*dart-server-analysis-server*" + (dart-server-executable-path) + (dart-server--analysis-server-snapshot-path)))) + (set-process-query-on-exit-flag dart-server-process nil) + (setq dart-server--analysis-server + (dart-server--analysis-server-create dart-server-process))) + + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (when (bound-and-true-p dart-server) + (dart-server--start-analysis-server-for-current-buffer) + (when (buffer-modified-p buffer) (dart-server-add-analysis-overlay)))))) + +(defun dart-server--analysis-server-create (process) + "Create a Dart analysis server from PROCESS." + (-let [instance (dart-server--make-analysis-server + :process process + :buffer (generate-new-buffer (process-name process)))] + (buffer-disable-undo (dart-server--analysis-server-buffer instance)) + (set-process-filter + process + (lambda (_ string) + (dart-server--analysis-server-process-filter instance string))) + instance)) + +(defun dart-server-add-analysis-overlay () + "Report to the Dart analysis server that it should overlay this buffer. + +The Dart analysis server allows clients to 'overlay' file contents with +a client-supplied string. This is needed because we want Emacs to report +errors for the current contents of the buffer, not whatever is saved to disk." + ;; buffer-file-name can be nil within revert-buffer, but in that case the + ;; buffer is just being reverted to its format on disk anyway. + (when buffer-file-name + (dart-server--analysis-server-send + "analysis.updateContent" + `((files + . ((,(dart-server--normalize-path buffer-file-name) + . ((type . "add") + (content + . ,(save-restriction (widen) (buffer-string))))))))))) + +(defun dart-server-change-analysis-overlay + (change-begin change-end change-before-length) + "Report to analysis server that it should change the overlay for this buffer. + +The region that changed ranges from CHANGE-BEGIN to CHANGE-END, and the +length of the text before the change is CHANGE-BEFORE-LENGTH. See also +`dart-server-add-analysis-overlay'." + (dart-server--analysis-server-send + "analysis.updateContent" + `((files + . ((,(dart-server--normalize-path buffer-file-name) + . ((type . "change") + (edits + . (((offset . ,(- change-begin 1)) + (length . ,change-before-length) + (replacement + . ,(buffer-substring change-begin change-end)))))))))))) + +(defun dart-server-remove-analysis-overlay () + "Remove the overlay for the current buffer since it has been saved. + +See also `dart-server-add-analysis-overlay'." + (dart-server--analysis-server-send + "analysis.updateContent" + `((files . ((,(dart-server--normalize-path buffer-file-name) . ((type . "remove")))))))) + +(defun dart-server-add-analysis-root-for-file (&optional file) + "Add the given FILE's root to the analysis server's analysis roots. + +A file's root is the pub root if it is in a pub package, or the file's directory +otherwise. If no FILE is given, then this will default to the variable +`buffer-file-name'." + (let* ((file-to-add (or file buffer-file-name)) + (pub-root (locate-dominating-file file-to-add "pubspec.yaml")) + (current-dir (file-name-directory file-to-add))) + (if pub-root + (dart-server-add-to-analysis-roots (directory-file-name (expand-file-name pub-root))) + (dart-server-add-to-analysis-roots (directory-file-name (expand-file-name current-dir)))))) + +(defun dart-server-add-to-analysis-roots (dir) + "Add DIR to the analysis server's analysis roots. + +The analysis roots are directories that contain Dart files. The analysis server +analyzes all Dart files under the analysis roots and provides information about +them when requested." + (add-to-list 'dart-server-analysis-roots (dart-server--normalize-path dir)) + (dart-server--send-analysis-roots)) + +(defun dart-server--send-analysis-roots () + "Send the current list of analysis roots to the analysis server." + (dart-server--analysis-server-send + "analysis.setAnalysisRoots" + `(("included" . ,dart-server-analysis-roots) + ("excluded" . nil)))) + +(defun dart-server--analysis-server-send (method &optional params callback) + "Send the METHOD request to the server with optional PARAMS. + +PARAMS should be JSON-encodable. If you provide a CALLBACK, it will be called +with the JSON decoded response. Otherwise, the output will just be checked." + (-let [req-without-id (dart-server--analysis-server-make-request method params)] + (dart-server--analysis-server-enqueue req-without-id callback))) + +(defun dart-server--analysis-server-make-request (method &optional params) + "Construct a request for the analysis server. + +The constructed request will call METHOD with optional PARAMS." + `((method . ,method) (params . ,params))) + +(defun dart-server--analysis-server-on-error-callback (response) + "If RESPONSE has an error, report it." + (-when-let (resp-err (assoc-default 'error response)) + (error "Analysis server error: %s" (assoc-default 'message resp-err)))) + +(defun dart-server--analysis-server-enqueue (req-without-id callback) + "Send REQ-WITHOUT-ID to the analysis server, call CALLBACK with the result." + (setq dart-server--analysis-server-next-id (1+ dart-server--analysis-server-next-id)) + (-let [request + (json-encode (cons (cons 'id (format "%s" dart-server--analysis-server-next-id)) + req-without-id))] + + ;; Enqueue the request so that we can be sure all requests are processed in + ;; order. + (push (cons dart-server--analysis-server-next-id + (or callback #'dart-server--analysis-server-on-error-callback)) + dart-server--analysis-server-callbacks) + + (cond + ((not dart-server--analysis-server) + (message "Starting Dart analysis server.") + (dart-server-start-analysis-server)) + ((not (process-live-p (dart-server--analysis-server-process dart-server--analysis-server))) + (message "Dart analysis server crashed, restarting.") + (dart-server-start-analysis-server))) + + (dart-server-info (concat "Sent: " request)) + (process-send-string (dart-server--analysis-server-process dart-server--analysis-server) + (concat request "\n")))) + +(cl-defun dart-server--analysis-server-process-filter (das string) + "Handle the event or method response from the dart analysis server. + +The server DAS has STRING added to the buffer associated with it. +Method responses are paired according to their pending request and +the callback for that request is given the json decoded response." + (-let [buf (dart-server--analysis-server-buffer das)] + ;; The buffer may have been killed if the server was restarted + (unless (buffer-live-p buf) + (cl-return-from dart-server--analysis-server-process-filter)) + + ;; We use a buffer here because emacs might call the filter before the + ;; entire line has been written out. In this case we store the + ;; unterminated line in a buffer to be read when the rest of the line is + ;; output. + (with-current-buffer buf + (goto-char (point-max)) + (insert string) + (-let [buf-lines (s-lines (buffer-string))] + (delete-region (point-min) (point-max)) + (insert (-last-item buf-lines)) + + (-let [messages + (--filter (and it (not (string-empty-p it))) + (-butlast buf-lines))] + (dolist (message messages) + (dart-server-info (concat "Received: " message)) + (dart-server--analysis-server-handle-msg + (-let [json-array-type 'list] + (json-read-from-string message))))))))) + +(defun dart-server--analysis-server-handle-msg (msg) + "Handle the parsed MSG from the analysis server." + (-if-let* ((raw-id (dart-server--get msg 'id)) + (id (string-to-number raw-id))) + ;; This is a response to a request, so we should invoke a callback in + ;; dart-server--analysis-server-callbacks. + (-if-let (resp-closure (dart-server--get dart-server--analysis-server-callbacks id)) + (progn + (setq dart-server--analysis-server-callbacks + (assq-delete-all id dart-server--analysis-server-callbacks)) + (funcall resp-closure msg)) + (-if-let (err (dart-server--get msg 'error)) + (dart-server--analysis-server-on-error-callback msg) + (dart-server-info (format "No callback was associated with id %s" raw-id)))) + + ;; This is a notification, so we should invoke callbacks in + ;; dart-server--analysis-server-subscriptions. + (-when-let* ((event (dart-server--get msg 'event)) + (params (dart-server--get msg 'params)) + (callbacks (dart-server--get dart-server--analysis-server-subscriptions event))) + (dolist (callback callbacks) + (-let [subscription (cons event callback)] + (funcall callback params subscription)))))) + +(defun dart-server--analysis-server-subscribe (event callback) + "Registers CALLBACK to be called for each EVENT of the given type. + +CALLBACK should take two parameters: the event object and an +opaque subscription object that can be passed to +`dart-server--analysis-server-unsubscribe'. Returns the same opaque +subscription object." + (-if-let (cell (assoc event dart-server--analysis-server-subscriptions)) + (nconc cell (list callback)) + (push (cons event (list callback)) dart-server--analysis-server-subscriptions)) + (cons event callback)) + +(defun dart-server--analysis-server-unsubscribe (subscription) + "Unregisters the analysis server SUBSCRIPTION. + +SUBSCRIPTION is an opaque object provided by +`dart-server--analysis-server-subscribe'." + (-let [(event . callback) subscription] + (delq callback (assoc event dart-server--analysis-server-subscriptions)))) + +;;;; Flycheck Error Reporting + +(defun dart-server--flycheck-start (_ callback) + "Run the CHECKER and report the errors to the CALLBACK." + (dart-server-info (format "Checking syntax for %s" (current-buffer))) + (dart-server--analysis-server-send + "analysis.getErrors" + `((file . ,(dart-server--normalize-path (buffer-file-name)))) + (-let [buffer (current-buffer)] + (lambda (response) + (dart-server--report-errors response buffer callback))))) + +(when (fboundp 'flycheck-define-generic-checker) + (flycheck-define-generic-checker + 'dart-server-analysis-server + "Checks Dart source code for errors using Dart analysis server." + :start 'dart-server--flycheck-start + :modes '(dart-server))) + +(defun dart-server--report-errors (response buffer callback) + "Report the errors returned from the analysis server. + +The errors contained in RESPONSE from Dart analysis server run on BUFFER are +reported to CALLBACK." + (dart-server-info (format "Reporting to flycheck: %s" response)) + (-let [fly-errors (--map (dart-server--to-flycheck-err it buffer) + (dart-server--get response 'result 'errors))] + (dart-server-info (format "Parsed errors: %s" fly-errors)) + (funcall callback 'finished fly-errors))) + +(defun dart-server--to-flycheck-err (err buffer) + "Create a flycheck error from a dart ERR in BUFFER." + (when (fboundp 'flycheck-error-new) + (flycheck-error-new + :buffer buffer + :checker 'dart-server-analysis-server + :filename (dart-server--get err 'location 'file) + :line (dart-server--get err 'location 'startLine) + :column (dart-server--get err 'location 'startColumn) + :message (dart-server--get err 'message) + :level (dart-server--severity-to-level (dart-server--get err 'severity))))) + +(defun dart-server--severity-to-level (severity) + "Convert SEVERITY to a flycheck level." + (cond + ((string= severity "INFO") 'info) + ((string= severity "WARNING") 'warning) + ((string= severity "ERROR") 'error))) + +;;;; Hover + +(defun dart-server-show-hover (&optional show-in-buffer) + "Displays hover information for the current point. + +With a prefix argument, opens a new buffer rather than using the +minibuffer." + (interactive "P") + (-when-let (filename (dart-server--normalize-path (buffer-file-name))) + (let ((show-in-buffer show-in-buffer) + (buffer (current-buffer)) + (pos (point))) + (dart-server--analysis-server-send + "analysis.getHover" + `(("file" . ,filename) ("offset" . ,pos)) + (lambda (response) + (-when-let (hover (car (dart-server--get response 'result 'hovers))) + (dart-server--json-let hover + (offset + length + dartdoc + (element-description elementDescription) + (element-kind elementKind) + (is-deprecated isDeprecated) + parameter) + (setq is-deprecated (not (eq is-deprecated :json-false))) + + ;; Briefly highlight the region that's being shown. + (with-current-buffer buffer + (dart-server--flash-highlight offset length)) + + (with-temp-buffer + (when is-deprecated + (insert (dart-server--face-string "DEPRECATED" 'font-lock-warning-face) ?\n)) + + (when element-description + (insert (dart-server--highlight-description element-description) + (dart-server--face-string (concat " (" element-kind ")") 'italic)) + (when (or dartdoc parameter) (insert ?\n))) + (when parameter + (insert + (dart-server--highlight-description parameter) + (dart-server--face-string " (parameter type)" 'italic)) + (when dartdoc) (insert ?\n)) + (when dartdoc + (when (or element-description parameter) (insert ?\n)) + (insert (dart-server--highlight-dartdoc dartdoc (not show-in-buffer)))) + + (let ((text (buffer-string))) + (if show-in-buffer + (with-current-buffer-window + "*Dart Analysis*" nil nil + (insert text) + (dart-server-popup-mode) + + (setq dart-server--do-it-again-callback + (lambda () + (save-excursion + (with-current-buffer buffer + (goto-char pos) + (dart-server-show-hover t)))))) + (message "%s" text))))))))))) + +(defconst dart-server--highlight-keyword-re + (regexp-opt + '("get" "set" "as" "abstract" "class" "extends" "implements" "enum" "typedef" + "const" "covariant" "deferred" "factory" "final" "import" "library" "new" + "operator" "part" "static" "async" "sync" "var") + 'words) + "A regular expression that matches keywords.") + +(defun dart-server--highlight-description (description) + "Returns a highlighted copy of DESCRIPTION." + (with-temp-buffer + (insert description) + (goto-char (point-min)) + + (while (not (eq (point) (point-max))) + (cond + ;; A keyword. + ((looking-at dart-server--highlight-keyword-re) + (dart-server--fontify-excursion 'font-lock-keyword-face + (goto-char (match-end 0)))) + + ;; An identifier could be a function name or a type name. + ((looking-at dart-server--identifier-re) + (goto-char (match-end 0)) + (put-text-property + (match-beginning 0) (point) 'face + (if (dart-server--at-end-of-function-name-p) 'font-lock-function-name-face + 'font-lock-type-face)) + + (cl-case (char-after) + ;; Foo.bar() + (?. + (forward-char) + (dart-server--fontify-excursion 'font-lock-function-name-face + (dart-server--forward-identifier))) + + ;; Foo bar + (?\s + (forward-char) + (dart-server--fontify-excursion 'font-lock-variable-name-face + (dart-server--forward-identifier))))) + + ;; Anything else is punctuation that we ignore. + (t (forward-char)))) + + (buffer-string))) + +(defun dart-server--at-end-of-function-name-p () + "Returns whether the point is at the end of a function name." + (cl-case (char-after) + (?\( t) + (?< + (and (looking-at (concat "\\(" dart-server--identifier-re "\\|[<>]\\)*")) + (eq (char-after (match-end 0)) ?\())))) + +(defun dart-server--highlight-dartdoc (dartdoc truncate) + "Returns a higlighted copy of DARTDOC." + (with-temp-buffer + (insert dartdoc) + + ;; Cut off long dartdocs so that the full signature is always visible. + (when truncate + (forward-line 11) + (delete-region (- (point) 1) (point-max))) + + (goto-char (point-min)) + + (while (re-search-forward "\\[.*?\\]" nil t) + (put-text-property (match-beginning 0) (match-end 0) + 'face 'font-lock-reference-face)) + + (buffer-string))) + +;;;; Navigation + +(defun dart-server-goto () + (interactive) + (-when-let (filename (dart-server--normalize-path (buffer-file-name))) + (dart-server--analysis-server-send + "analysis.getNavigation" + `(("file" . ,filename) ("offset" . ,(point)) ("length" . 0)) + (lambda (response) + (-when-let (result (dart-server--get response 'result)) + (dart-server--json-let result (files targets regions) + (-when-let (region (car regions)) + (let* ((target-index (car (dart-server--get region 'targets))) + (target (elt targets target-index)) + + (file-index (dart-server--get target 'fileIndex)) + (offset (dart-server--get target 'offset)) + (length (dart-server--get target 'length)) + + (file (elt files file-index))) + (find-file file) + (goto-char (+ 1 offset)) + (dart-server--flash-highlight offset length))))))))) + +;;;; Search + +(defun dart-server-find-refs (pos &optional include-potential) + (interactive "dP") + (-when-let (filename (dart-server--normalize-path (buffer-file-name))) + (dart-server--analysis-server-send + "search.findElementReferences" + `(("file" . ,filename) + ("offset" . ,pos) + ("includePotential" . ,(or include-potential json-false))) + (let ((buffer (current-buffer)) + (include-potential include-potential)) + (lambda (response) + (-when-let (result (dart-server--get response 'result)) + (let ((name (dart-server--get result 'element 'name)) + (location (dart-server--get result 'element 'location))) + (dart-server--display-search-results + (dart-server--get result 'id) + (lambda () + (setq dart-server--do-it-again-callback + (lambda () + (with-current-buffer buffer + (dart-server-find-refs pos include-potential)))) + + (insert "References to ") + (insert-button + name + 'action (lambda (_) (dart-server--goto-location location))) + (insert ":\n\n")))))))))) + +(defun dart-server-find-member-decls (name) + "Find member declarations named NAME." + (interactive "sMember name: ") + (dart-server--find-by-name + "search.findMemberDeclarations" "name" name "Members named ")) + +(defun dart-server-find-member-refs (name) + "Find member references named NAME." + (interactive "sMember name: ") + (dart-server--find-by-name + "search.findMemberReferences" "name" name "References to ")) + +(defun dart-server-find-top-level-decls (name) + "Find top-level declarations named NAME." + (interactive "sDeclaration name: ") + (dart-server--find-by-name + "search.findTopLevelDeclarations" "pattern" name "Declarations matching ")) + +(defun dart-server--find-by-name (method argument name header) + "A helper function for running an analysis server search for NAME. + +Calls the given analysis server METHOD passing NAME to the given +ARGUMENT. Displays a header beginning with HEADER in the results." + (dart-server--analysis-server-send + method + (list (cons argument name)) + (lambda (response) + (-when-let (id (dart-server--get response 'result 'id)) + (dart-server--display-search-results + id + (lambda () + (setq dart-server--do-it-again-callback + (lambda () + (dart-server--find-by-name method argument name header))) + (insert header name ":\n\n"))))))) + +(defun dart-server--display-search-results (search-id callback) + "Displays search results with the given SEARCH-ID. + +CALLBACK is called with no arguments in the search result buffer +to add a header and otherwise prepare it for displaying results." + (let (buffer + beginning-of-results + (total-results 0)) + (with-current-buffer-window + "*Dart Search*" nil nil + (dart-server-popup-mode) + (setq buffer (current-buffer)) + (funcall callback) + (setq beginning-of-results (point)) + + (dart-server--analysis-server-subscribe + "search.results" + (lambda (event subscription) + (with-current-buffer buffer + (dart-server--json-let event (id results (is-last isLast)) + (when (equal id search-id) + (-let [buffer-read-only nil] + (save-excursion + (goto-char (point-max)) + (dolist (result results) + (let ((location (dart-server--get result 'location)) + (path (dart-server--get result 'path)) + (start (point))) + (dart-server--fontify-excursion '(compilation-info underline) + (when (cl-some + (lambda (element) + (equal (dart-server--get element 'kind) "CONSTRUCTOR")) + path) + (insert "new ")) + + (insert + (->> path + (--remove (member (dart-server--get it 'kind) + '("COMPILATION_UNIT" "FILE" "LIBRARY" "PARAMETER"))) + (--map (dart-server--get it 'name)) + (-remove 'string-empty-p) + nreverse + (s-join "."))) + + (make-text-button + start (point) + 'action (lambda (_) (dart-server--goto-location location)))) + + (dart-server--json-let location (file (line startLine) (column startColumn)) + (insert " " file ":" + (dart-server--face-string line 'compilation-line-number) ":" + (dart-server--face-string column 'compilation-column-number) ?\n))))) + + (setq total-results (+ total-results (length results))) + + (when (eq is-last t) + (dart-server--analysis-server-unsubscribe subscription) + (save-excursion + (goto-char (point-max)) + (insert "\nFound " (dart-server--face-string total-results 'bold) " results.")))))))))) + + (select-window (get-buffer-window buffer)) + (goto-char beginning-of-results))) + +(defun dart-server--goto-location (location) + "Sends the user to the analysis server LOCATION." + (dart-server--json-let location (file offset length) + (find-file file) + (goto-char (+ 1 offset)) + (dart-server--flash-highlight offset length))) + +;;;; Auto-complete + +(defcustom dart-server-expand-fallback (key-binding (kbd "M-/")) + "The fallback command to use for `dart-server-expand'. + +This is used when the analysis server isn't available. It +defaults to the command globally bound to M-/." + :group 'dart-server + :type 'function + :package-version '(dart-server . "0.1.0")) + +(defvar dart-server--last-expand-results nil + "The results of the last call to `dart-server-expand'.") + +(defvar dart-server--last-expand-beginning nil + "The marker for the beginning of the text inserted by the last call to `dart-server-expand'.") + +(defvar dart-server--last-expand-end nil + "The marker for the end of the text inserted by the last call to `dart-server-expand'.") + +(defvar dart-server--last-expand-index nil + "The index into `dart-server--last-expand-results' for the last call to `dart-server-expand'.") + +(defvar dart-server--last-expand-parameters-index nil + "The index into for the last parameter suggestion from `dart-server-expand-parameters'. + +This is an index into the paramaterNames and parameterTypes list +in the suggestion identified by `dart-server--last-expand-index', and +into `dart-server--last-expand-parameters-ranges'.") + +(defvar dart-server--last-expand-parameters-ranges nil + "The list of parameter ranges for the last call to `dart-server-expand-parameters'. + +This is a list of pairs of markers. Each pair identifies the +beginning and end of a parameter in the parameter list generated +by `dart-server-expand-parameters'`. + +Note that the end markers are placed one character after the +actual ending of the parameter. This ensures that if the marker +stayas in place when the parameter is overwritten.") + +(defvar dart-server--last-expand-subscription nil + "The last analysis server subscription from a call to `dart-server-expand'.") + +(cl-defun dart-server-expand () + "Expand previous word using Dart's autocompletion." + (interactive "*") + (unless dart-server-enable-analysis-server + (call-interactively dart-server-expand-fallback t) + (cl-return-from dart-server-expand)) + + (when (and (memq last-command '(dart-server-expand dart-server-expand-parameters)) + dart-server--last-expand-results) + (cl-incf dart-server--last-expand-index) + (when (>= dart-server--last-expand-index (length dart-server--last-expand-results)) + (setq dart-server--last-expand-index 0)) + (dart-server--use-expand-suggestion + dart-server--last-expand-beginning + dart-server--last-expand-end + (elt dart-server--last-expand-results dart-server--last-expand-index)) + (cl-return-from dart-server-expand)) + + (when dart-server--last-expand-subscription + (dart-server--analysis-server-unsubscribe dart-server--last-expand-subscription)) + (setq dart-server--last-expand-results nil) + (setq dart-server--last-expand-beginning nil) + (setq dart-server--last-expand-end nil) + (setq dart-server--last-expand-index nil) + (setq dart-server--last-expand-subscription nil) + + (-when-let (filename (dart-server--normalize-path (buffer-file-name))) + (dart-server--analysis-server-send + "completion.getSuggestions" + `(("file" . ,filename) + ("offset" . ,(- (point) 1))) + (let ((buffer (current-buffer)) + (first t)) + (lambda (response) + (-when-let (completion-id (dart-server--get response 'result 'id)) + (dart-server--analysis-server-subscribe + "completion.results" + (setq dart-server--last-expand-subscription + (lambda (event subscription) + (dart-server--json-let event + (id results + (offset replacementOffset) + (length replacementLength) + (is-last isLast)) + (when is-last (dart-server--analysis-server-unsubscribe subscription)) + + (when (equal id completion-id) + (with-current-buffer buffer + (dart-server--handle-completion-event results offset length first)) + (setq first nil)))))))))))) + +(defun dart-server--handle-completion-event (results offset length first) + "Handles a completion results event. + +If FIRST is non-nil, this is the first completion event for this completion." + ;; Get rid of any suggestions that don't match existing characters. The + ;; analysis server provides extra suggestions to support search-as-you-type, + ;; but we don't do that. + (when (> length 0) + (-let [text (buffer-substring (+ offset 1) (+ offset length 1))] + (setq results + (--remove (string-prefix-p text (dart-server--get it 'completion) t) + results)))) + + (when (> (length results) 0) + ;; Fill the first result so the first call does something. Just save later + ;; results for future calls. + (when first + (setq dart-server--last-expand-index 0) + (setq dart-server--last-expand-beginning (copy-marker (+ offset 1))) + (dart-server--use-expand-suggestion (+ offset 1) (+ offset length 1) (car results))) + + (setq first nil) + (setq dart-server--last-expand-results results))) + +(defun dart-server--use-expand-suggestion (beginning end suggestion) + "Inserts SUGGESTION between BEGINNING and END." + (dart-server--json-let suggestion + (completion element + (selection-offset selectionOffset) + (is-deprecated isDeprecated) + (doc-summary docSummary)) + (goto-char beginning) + (delete-region beginning end) + (save-excursion + (insert completion) + (setq dart-server--last-expand-end (point-marker))) + (forward-char selection-offset) + + (with-temp-buffer + (when (eq is-deprecated t) + (insert (dart-server--face-string "DEPRECATED" 'font-lock-warning-face) ?\n)) + + (insert (dart-server--highlight-description (dart-server--description-of-element element))) + (when doc-summary + (insert ?\n ?\n (dart-server--highlight-dartdoc doc-summary nil))) + + (message "%s" (buffer-string))))) + +(defun dart-server--description-of-element (element) + "Returns a textual description of an analysis server ELEMENT." + (dart-server--json-let element + (kind name parameters + (return-type returnType) + (type-parameters typeParameters)) + (with-temp-buffer + (if (equal kind "CONSTRUCTOR") + (progn + (insert "new " return-type) + (unless (string-empty-p name) + (insert "." name)) + (insert parameters) + (insert " → " return-type)) + + (cl-case kind + ("GETTER" (insert "get ")) + ("SETTER" (insert "set "))) + (insert name) + (when type-parameters (insert type-parameters)) + (when parameters (insert parameters)) + (when return-type (insert " → " return-type))) + (buffer-string)))) + +(cl-defun dart-server-expand-parameters () + "Adds parameters to the currently-selected `dart-server-expand' completion. + +This will select the first parameter, if one exists." + (interactive "*") + (cond + ((and (eq last-command 'dart-server-expand) + dart-server--last-expand-results) + + ;; If this is called directly after `dart-server-expand', create the parameter list + ;; and highlight the first entry. + (setq dart-server--last-expand-parameters-index 0) + (dart-server--json-let (elt dart-server--last-expand-results dart-server--last-expand-index) + ((parameter-names parameterNames) + (argument-string defaultArgumentListString) + (argument-ranges defaultArgumentListTextRanges)) + (unless parameter-names (cl-return-from dart-server-expand-parameters)) + + (unless argument-string + (insert ?\() + (save-excursion + (insert ?\)) + (setq dart-server--last-expand-end (point-marker))) + (cl-return-from dart-server-expand-parameters)) + + (save-excursion + (insert ?\( argument-string ?\)) + (setq dart-server--last-expand-end (point-marker))) + + (setq dart-server--last-expand-parameters-ranges + (cl-loop for i below (length argument-ranges) by 2 + collect (let* ((beginning (+ (point) 1 (elt argument-ranges i))) + (end (+ beginning (elt argument-ranges (+ i 1)) 1))) + (list (copy-marker beginning) (copy-marker end))))) + + (dart-server--expand-select-parameter))) + + ((and (< dart-server--last-expand-beginning (point) dart-server--last-expand-end) + dart-server--last-expand-parameters-index) + + ;; If this is called when the point is within the text generated by the + ;; last `dart-server-expand-parameters' call, move to the next parameter in the + ;; list. + (cl-incf dart-server--last-expand-parameters-index) + (when (>= dart-server--last-expand-parameters-index (length dart-server--last-expand-parameters-ranges)) + (setq dart-server--last-expand-parameters-index 0)) + + (dart-server--expand-select-parameter)))) + +(defun dart-server--expand-select-parameter () + "Selects the parameter indicated by expansion variables." + (-let [(beginning end) (elt dart-server--last-expand-parameters-ranges + dart-server--last-expand-parameters-index)] + (dart-server--delsel-range beginning (- end 1))) + + (dart-server--json-let (elt dart-server--last-expand-results dart-server--last-expand-index) + ((parameter-names parameterNames) + (parameter-types parameterTypes)) + (message "%s" (dart-server--highlight-description + (concat (elt parameter-types dart-server--last-expand-parameters-index) " " + (elt parameter-names dart-server--last-expand-parameters-index)))))) + +(defun dart-server--delsel-range (beginning end) + "Highlights the range between BEGINNING and END and enables `delete-selection-mode' temporarily." + (setq transient-mark-mode nil) + (goto-char beginning) + (push-mark nil t) + (goto-char end) + + ;; Run this in a timer because `activate-mark' doesn't seem to work + ;; directly, and because we don't want to disable `delete-selection-mode' + ;; when `post-command-hook' is invoked after the calling command finishes. + (run-at-time + "0 sec" nil + (lambda () + (activate-mark) + + ;; Overwrite the current selection, but don't globally enable + ;; delete-selection-mode. + (unless delete-selection-mode + (delete-selection-mode 1) + (add-hook 'post-command-hook #'dart-server--disable-delsel t t))))) + +(defun dart-server--disable-delsel () + "Disables `delete-selection-mode' and deactivates the mark. + +Also removes this function from `post-command-hook'." + (deactivate-mark) + (delete-selection-mode 0) + (remove-hook 'post-command-hook 'dart-server--disable-delsel t)) + + +;;; Popup Mode + +(define-derived-mode dart-server-popup-mode fundamental-mode "DartPopup" + "Major mode for popups." + :mode 'dart-server-popup + (use-local-map dart-server-popup-mode-map)) + +(put 'dart-server-popup-mode 'mode-class 'special) + +(defvar dart-server-popup-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map help-mode-map) + (define-key map (kbd "g") 'dart-server-do-it-again) + ;; Unbind help-specific keys. + (define-key map (kbd "RET") nil) + (define-key map (kbd "l") nil) + (define-key map (kbd "r") nil) + (define-key map (kbd "") nil) + (define-key map (kbd "") nil) + (define-key map (kbd "") nil) + (define-key map (kbd "C-c C-b") nil) + (define-key map (kbd "C-c C-c") nil) + (define-key map (kbd "C-c C-f") nil) + map) + "Keymap used in Dart popup buffers.") + +(defun dart-server-do-it-again () + "Re-runs the logic that generated the current buffer." + (interactive) + (when dart-server--do-it-again-callback + (funcall dart-server--do-it-again-callback))) + + +;;; Formatting + +(defcustom dart-server-formatter-command-override nil + "The command for running the Dart formatter. + +Don't read this variable; call `dart-server-formatter-command' instead." + :type 'string + :group 'dart-server + :package-version '(dart-server . "0.1.0")) + +(defcustom dart-server-formatter-line-length 80 + "The line length to use when running the Dart formatter." + :type 'integer + :group 'dart-server + :package-version '(dart-server . "0.1.0")) + +(defcustom dart-server-format-on-save nil + "Whether to run the Dart formatter before saving." + :type 'boolean + :group 'dart-server + :package-version '(dart-server . "0.1.0")) + +(defcustom dart-server-formatter-show-errors 'buffer + "Where to display Dart formatter error output. +It can either be displayed in its own buffer, in the echo area, or not at all. + +Please note that Emacs outputs to the echo area when writing +files and will overwrite the formatter's echo output if used from +inside a `before-save-hook'." + :type '(choice + (const :tag "Own buffer" buffer) + (const :tag "Echo area" echo) + (const :tag "None" nil)) + :group 'dart-server) + +(defun dart-server-formatter-command () + "The command for running the Dart formatter. + +This can be customized by setting `dart-server-formatter-command-override'." + (or dart-server-formatter-command-override + (when dart-server-sdk-path + (concat dart-server-sdk-path + (file-name-as-directory "bin") + "dartfmt")))) + +(defvar dart-server--formatter-compilation-regexp + '("^line \\([0-9]+\\), column \\([0-9]+\\) of \\([^ \n]+\\):" 3 1 2) + "Regular expresion to match errors in the formatter's output. +See `compilation-error-regexp-alist' for help on their format.") + +(add-to-list 'compilation-error-regexp-alist-alist + (cons 'dart-server-formatter dart-server--formatter-compilation-regexp)) +(add-to-list 'compilation-error-regexp-alist 'dart-server-formatter) + +(cl-defun dart-server-format () + "Format the current buffer using the Dart formatter. + +By default, this uses the formatter in `dart-server-sdk-path'. However, +this can be overridden by customizing +`dart-server-formatter-command-override'." + (interactive) + (let* ((file (make-temp-file "format" nil ".dart")) + (patch-buffer (get-buffer-create "*Dart formatter patch*")) + (error-buffer (when dart-server-formatter-show-errors + (get-buffer-create "*Dart formatter errors*"))) + (coding-system-for-read 'utf-8) + (coding-system-for-write 'utf-8) + (args `("--line-length" ,(number-to-string dart-server-formatter-line-length) + "--overwrite" ,file))) + (unwind-protect + (save-restriction + (widen) + + (when error-buffer + (with-current-buffer error-buffer + (setq buffer-read-only nil) + (erase-buffer))) + + (write-region nil nil file nil 'no-message) + (dart-server-info (format "%s %s" (dart-server-formatter-command) args)) + + (unless (zerop (apply #'call-process (dart-server-formatter-command) nil error-buffer nil args)) + (message "Formatting failed") + (when error-buffer + (dart-server--formatter-show-errors error-buffer file (buffer-file-name))) + (cl-return-from dart-server-format)) + + ;; Apply the format as a diff so that only portions of the buffer that + ;; actually change are marked as modified. + (if (zerop (call-process-region (point-min) (point-max) + "diff" nil patch-buffer nil "--rcs" "-" file)) + (message "Buffer is already formatted") + (dart-server--apply-rcs-patch patch-buffer) + (message "Formatted buffer")) + (when error-buffer (dart-server--kill-buffer-and-window error-buffer))) + (kill-buffer patch-buffer) + (delete-file file)))) + +(defun dart-server--do-format-on-save () + "Format the buffer if `dart-server-format-on-save' is non-nil." + (when dart-server-format-on-save + (dart-server-format))) + +(defun dart-server--apply-rcs-patch (patch-buffer) + "Apply an RCS diff from PATCH-BUFFER to the current buffer." + (let ((target-buffer (current-buffer)) + ;; The relative offset between line numbers in the buffer and in patch. + ;; + ;; Line numbers in the patch are based on the source file, so we have to + ;; keep an offset when making changes to the buffer. + ;; + ;; Appending lines decrements the offset (possibly making it negative), + ;; deleting lines increments it. This order simplifies the forward-line + ;; invocations. + (line-offset 0)) + (save-excursion + (with-current-buffer patch-buffer + (goto-char (point-min)) + (while (not (eobp)) + (unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)") + (error "Invalid RCS patch or internal error in dart-server--apply-rcs-patch")) + + (forward-line) + (let ((action (match-string 1)) + (from (string-to-number (match-string 2))) + (len (string-to-number (match-string 3)))) + (cond + ((equal action "a") + (-let [start (point)] + (forward-line len) + (-let [text (buffer-substring start (point))] + (with-current-buffer target-buffer + (cl-decf line-offset len) + (goto-char (point-min)) + (forward-line (- from len line-offset)) + (insert text))))) + + ((equal action "d") + (with-current-buffer target-buffer + (goto-char (point-min)) + (forward-line (- from line-offset 1)) + (cl-incf line-offset len) + (dart-server--delete-whole-line len))) + + (t + (error "Invalid RCS patch or internal error in dart-server--apply-rcs-patch"))))))))) + +(defun dart-server--formatter-show-errors (error-buffer temp-file real-file) + "Display formatter errors in `error-buffer'. +This replaces references to TEMP-FILE with REAL-FILE." + (with-current-buffer error-buffer + (-let [echo (eq dart-server-formatter-show-errors 'echo)] + (goto-char (point-min)) + (-let [regexp (concat "\\(" (regexp-quote temp-file) "\\):")] + (while (search-forward-regexp regexp nil t) + (replace-match (file-name-nondirectory real-file) t t nil 1))) + + (if echo + (progn + (message "%s" (buffer-string)) + (dart-server--kill-buffer-and-window error-buffer)) + (compilation-mode) + (temp-buffer-window-show error-buffer) + (select-window (get-buffer-window error-buffer)))))) + + +;;; Initialization + +;;;###autoload +(define-minor-mode dart-server nil nil nil nil + (if dart-server + (add-hook 'before-save-hook #'dart-server--do-format-on-save nil t) + (remove-hook 'before-save-hook #'dart-server--do-format-on-save t))) + +(provide 'dart-server) + +;;; dart-server.el ends here diff --git a/elpa/dart-server-20190817.1254/dart-server.elc b/elpa/dart-server-20190817.1254/dart-server.elc new file mode 100644 index 0000000000000000000000000000000000000000..752076b85a4503a65376ce9d1011765ca567b2b7 GIT binary patch literal 55567 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 z

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 literal 0 HcmV?d00001 diff --git a/elpa/dart-server-readme.txt b/elpa/dart-server-readme.txt new file mode 100644 index 00000000..9d367996 --- /dev/null +++ b/elpa/dart-server-readme.txt @@ -0,0 +1,4 @@ +Minor mode for editing Dart files. + +Provides dart server features, such as formatting, analysis, +flycheck, etc. diff --git a/elpa/flycheck-20200405.2310/flycheck-autoloads.el b/elpa/flycheck-20200405.2310/flycheck-autoloads.el new file mode 100644 index 00000000..1ab2daf9 --- /dev/null +++ b/elpa/flycheck-20200405.2310/flycheck-autoloads.el @@ -0,0 +1,273 @@ +;;; 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 configuration files for the given syntax CHECKER. +CUSTOM-ARGS are forwarded to `defcustom'. + +FILE-NAME is the initial value of the new variable. If omitted, +the default value is nil. It can be either a string or a list of +strings. + +Use this together with the `config-file' form in the `:command' +argument to `flycheck-define-checker'. + +\(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) + +(autoload 'flycheck-define-checker "flycheck" "\ +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'. + +\(fn SYMBOL DOCSTRING &rest PROPERTIES)" nil t) + +(function-put 'flycheck-define-checker 'lisp-indent-function '1) + +(function-put 'flycheck-define-checker 'doc-string-elt '2) + +(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-20200405.2310/flycheck-buttercup.el b/elpa/flycheck-20200405.2310/flycheck-buttercup.el new file mode 100644 index 00000000..98022659 --- /dev/null +++ b/elpa/flycheck-20200405.2310/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-20200405.2310/flycheck-ert.el b/elpa/flycheck-20200405.2310/flycheck-ert.el new file mode 100644 index 00000000..c58b2948 --- /dev/null +++ b/elpa/flycheck-20200405.2310/flycheck-ert.el @@ -0,0 +1,495 @@ +;;; flycheck-ert.el --- Flycheck: ERT extensions -*- lexical-binding: t; -*- + +;; Copyright (C) 2017-2018 Flycheck contributors +;; Copyright (C) 2013-2016 Sebastian Wiesner and Flycheck contributors + +;; Author: Sebastian Wiesner +;; Maintainer: Clément Pit-Claudel +;; fmdkdd +;; URL: https://github.com/flycheck/flycheck + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Unit testing library for Flycheck, the modern on-the-fly syntax checking +;; extension for GNU Emacs. + +;; Provide various utility functions and unit test helpers to test Flycheck and +;; Flycheck extensions. + +;;; Code: + +(require 'flycheck) +(require 'ert) +(require 'macroexp) ; For macro utilities + + +;;; Compatibility + +(eval-and-compile + ;; Provide `ert-skip' and friends for Emacs 24.3 + (defconst flycheck-ert-ert-can-skip (fboundp 'ert-skip) + "Whether ERT supports test skipping.") + + (unless (fboundp 'define-error) + ;; from Emacs `subr.el' + (defun define-error (name message &optional parent) + "Define NAME as a new error signal. +MESSAGE is a string that will be output to the echo area if such an error +is signaled without being caught by a `condition-case'. +PARENT is either a signal or a list of signals from which it inherits. +Defaults to `error'." + (unless parent (setq parent 'error)) + (let ((conditions + (if (consp parent) + (apply #'append + (mapcar + (lambda (parent) + (cons parent + (or (get parent 'error-conditions) + (error "Unknown signal `%s'" parent)))) + parent)) + (cons parent (get parent 'error-conditions))))) + (put name 'error-conditions + (delete-dups (copy-sequence (cons name conditions)))) + (when message (put name 'error-message message))))) + + (unless flycheck-ert-ert-can-skip + ;; Fake skipping + + (define-error 'flycheck-ert-skipped "Test skipped") + + (defun ert-skip (data) + (signal 'flycheck-ert-skipped data)) + + (defmacro skip-unless (form) + `(unless (ignore-errors ,form) + (signal 'flycheck-ert-skipped ',form))) + + (defun ert-test-skipped-p (result) + (and (ert-test-failed-p result) + (eq (car (ert-test-failed-condition result)) + 'flycheck-ert-skipped))))) + + +;;; Internal variables + +(defvar flycheck-ert--resource-directory nil + "The directory to get resources from in this test suite.") + + +;;; Resource management macros + +(defmacro flycheck-ert-with-temp-buffer (&rest body) + "Eval BODY within a temporary buffer. + +Like `with-temp-buffer', but resets the modification state of the +temporary buffer to make sure that it is properly killed even if +it has a backing file and is modified." + (declare (indent 0) (debug t)) + `(with-temp-buffer + (unwind-protect + ,(macroexp-progn body) + ;; Reset modification state of the buffer, and unlink it from its backing + ;; file, if any, because Emacs refuses to kill modified buffers with + ;; backing files, even if they are temporary. + (set-buffer-modified-p nil) + (set-visited-file-name nil 'no-query)))) + +(defmacro flycheck-ert-with-file-buffer (file-name &rest body) + "Create a buffer from FILE-NAME and eval BODY. + +BODY is evaluated with `current-buffer' being a buffer with the +contents FILE-NAME." + (declare (indent 1) (debug t)) + `(let ((file-name ,file-name)) + (unless (file-exists-p file-name) + (error "%s does not exist" file-name)) + (flycheck-ert-with-temp-buffer + (insert-file-contents file-name 'visit) + (set-visited-file-name file-name 'no-query) + (cd (file-name-directory file-name)) + ;; Mark the buffer as not modified, because we just loaded the file up to + ;; now. + (set-buffer-modified-p nil) + ,@body))) + +(defmacro flycheck-ert-with-help-buffer (&rest body) + "Execute BODY and kill the help buffer afterwards. + +Use this macro to test functions that create a Help buffer." + (declare (indent 0)) + `(unwind-protect + ,(macroexp-progn body) + (when (buffer-live-p (get-buffer (help-buffer))) + (kill-buffer (help-buffer))))) + +(defmacro flycheck-ert-with-global-mode (&rest body) + "Execute BODY with Global Flycheck Mode enabled. + +After BODY, restore the old state of Global Flycheck Mode." + (declare (indent 0)) + `(let ((old-state global-flycheck-mode)) + (unwind-protect + (progn + (global-flycheck-mode 1) + ,@body) + (global-flycheck-mode (if old-state 1 -1))))) + +(defmacro flycheck-ert-with-env (env &rest body) + "Add ENV to `process-environment' in BODY. + +Execute BODY with a `process-environment' which contains all +variables from ENV added. + +ENV is an alist, where each cons cell `(VAR . VALUE)' is a +environment variable VAR to be added to `process-environment' +with VALUE." + (declare (indent 1)) + `(let ((process-environment (copy-sequence process-environment))) + (pcase-dolist (`(,var . ,value) ,env) + (setenv var value)) + ,@body)) + + +;;; Test resources +(defun flycheck-ert-resource-filename (resource-file) + "Determine the absolute file name of a RESOURCE-FILE. + +Relative file names are expanded against +`flycheck-ert--resource-directory'." + (expand-file-name resource-file flycheck-ert--resource-directory)) + +(defmacro flycheck-ert-with-resource-buffer (resource-file &rest body) + "Create a temp buffer from a RESOURCE-FILE and execute BODY. + +The absolute file name of RESOURCE-FILE is determined with +`flycheck-ert-resource-filename'." + (declare (indent 1)) + `(flycheck-ert-with-file-buffer + (flycheck-ert-resource-filename ,resource-file) + ,@body)) + + +;;; Test suite initialization + +(defun flycheck-ert-initialize (resource-dir) + "Initialize a test suite with RESOURCE-DIR. + +RESOURCE-DIR is the directory, `flycheck-ert-resource-filename' +should use to lookup resource files." + (when flycheck-ert--resource-directory + (error "Test suite already initialized")) + (let ((tests (ert-select-tests t t))) + ;; Select all tests + (unless tests + (error "No tests defined. \ +Call `flycheck-ert-initialize' after defining all tests!")) + + (setq flycheck-ert--resource-directory resource-dir) + + ;; Emacs 24.3 don't support skipped tests, so we add poor man's test + ;; skipping: We mark skipped tests as expected failures by adjusting the + ;; expected result of all test cases. Not particularly pretty, but works :) + (unless flycheck-ert-ert-can-skip + (dolist (test tests) + (let ((result (ert-test-expected-result-type test))) + (setf (ert-test-expected-result-type test) + `(or ,result (satisfies ert-test-skipped-p)))))))) + + +;;; Test case definitions +(defmacro flycheck-ert-def-checker-test (checker language name + &rest keys-and-body) + "Define a test case for a syntax CHECKER for LANGUAGE. + +CHECKER is a symbol or a list of symbols denoting syntax checkers +being tested by the test. The test case is skipped, if any of +these checkers cannot be used. LANGUAGE is a symbol or a list of +symbols denoting the programming languages supported by the +syntax checkers. This is currently only used for tagging the +test appropriately. + +NAME is a symbol denoting the local name of the test. The test +itself is ultimately named +`flycheck-define-checker/CHECKER/NAME'. If CHECKER is a list, +the first checker in the list is used for naming the test. + +Optionally, the keyword arguments `:tags' and `:expected-result' +may be given. They have the same meaning as in `ert-deftest.', +and are added to the tags and result expectations set up by this +macro. + +The remaining forms KEYS-AND-BODY denote the body of the test +case, including assertions and setup code." + (declare (indent 3)) + (unless checker + (error "No syntax checkers specified")) + (unless language + (error "No languages specified")) + (let* ((checkers (if (symbolp checker) (list checker) checker)) + (checker (car checkers)) + (languages (if (symbolp language) (list language) language)) + (language-tags (mapcar (lambda (l) (intern (format "language-%s" l))) + languages)) + (checker-tags (mapcar (lambda (c) (intern (format "checker-%s" c))) + checkers)) + (local-name (or name 'default)) + (full-name (intern (format "flycheck-define-checker/%s/%s" + checker local-name))) + (keys-and-body (ert--parse-keys-and-body keys-and-body)) + (body (cadr keys-and-body)) + (keys (car keys-and-body)) + (default-tags '(syntax-checker external-tool))) + `(ert-deftest ,full-name () + :expected-result ,(or (plist-get keys :expected-result) :passed) + :tags (append ',(append default-tags language-tags checker-tags) + ,(plist-get keys :tags)) + ,@(mapcar (lambda (c) + `(skip-unless + ;; Ignore non-command checkers + (or (not (flycheck-checker-get ',c 'command)) + (executable-find (flycheck-checker-executable ',c))))) + checkers) + ,@body))) + + +;;; Test case results + +(defun flycheck-ert-syntax-check-timed-out-p (result) + "Whether RESULT denotes a timed-out test. + +RESULT is an ERT test result object." + (and (ert-test-failed-p result) + (eq (car (ert-test-failed-condition result)) + 'flycheck-ert-syntax-check-timed-out))) + + +;;; Syntax checking in tests + +(defvar-local flycheck-ert-syntax-checker-finished nil + "Non-nil if the current checker has finished.") + +(add-hook 'flycheck-after-syntax-check-hook + (lambda () (setq flycheck-ert-syntax-checker-finished t))) + +(defconst flycheck-ert-checker-wait-time 10 + "Time to wait until a checker is finished in seconds. + +After this time has elapsed, the checker is considered to have +failed, and the test aborted with failure.") + +(define-error 'flycheck-ert-syntax-check-timed-out "Syntax check timed out.") + +(defun flycheck-ert-wait-for-syntax-checker () + "Wait until the syntax check in the current buffer is finished." + (let ((starttime (float-time))) + (while (and (not flycheck-ert-syntax-checker-finished) + (< (- (float-time) starttime) flycheck-ert-checker-wait-time)) + (accept-process-output nil 0.02)) + (unless (< (- (float-time) starttime) flycheck-ert-checker-wait-time) + (flycheck-stop) + (signal 'flycheck-ert-syntax-check-timed-out nil))) + (setq flycheck-ert-syntax-checker-finished nil)) + +(defun flycheck-ert-buffer-sync () + "Like `flycheck-buffer', but synchronously." + (setq flycheck-ert-syntax-checker-finished nil) + (should (not (flycheck-running-p))) + (flycheck-mode) ;; This will only start a deferred check, + (should (flycheck-get-checker-for-buffer)) + (flycheck-buffer) ;; …so we need an explicit manual check + ;; After starting the check, the checker should either be running now, or + ;; already be finished (if it was fast). + (should (or flycheck-current-syntax-check + flycheck-ert-syntax-checker-finished)) + ;; Also there should be no deferred check pending anymore + (should-not (flycheck-deferred-check-p)) + (flycheck-ert-wait-for-syntax-checker)) + +(defun flycheck-ert-ensure-clear () + "Clear the current buffer. + +Raise an assertion error if the buffer is not clear afterwards." + (flycheck-clear) + (should (not flycheck-current-errors)) + (should (not (-any? (lambda (ov) (overlay-get ov 'flycheck-overlay)) + (overlays-in (point-min) (point-max)))))) + + +;;; Test assertions + +(defun flycheck-error-without-group (err) + "Return a copy ERR with the `group' property set to nil." + (let ((copy (copy-flycheck-error err))) + (setf (flycheck-error-group copy) nil) + copy)) + +(defun flycheck-ert-should-overlay (error) + "Test that ERROR has a proper overlay in the current buffer. + +ERROR is a Flycheck error object." + (let* ((overlay (-first (lambda (ov) + (equal (flycheck-error-without-group + (overlay-get ov 'flycheck-error)) + (flycheck-error-without-group error))) + (flycheck-overlays-in 0 (+ 1 (buffer-size))))) + (region + ;; Overlays of errors from other files are on the first line + (if (flycheck-relevant-error-other-file-p error) + (cons (point-min) + (save-excursion (goto-char (point-min)) (point-at-eol))) + (flycheck-error-region-for-mode error 'symbols))) + (level (flycheck-error-level error)) + (category (flycheck-error-level-overlay-category level)) + (face (get category 'face)) + (fringe-bitmap (flycheck-error-level-fringe-bitmap level)) + (fringe-face (flycheck-error-level-fringe-face level)) + (fringe-icon (list 'left-fringe fringe-bitmap fringe-face))) + (should overlay) + (should (overlay-get overlay 'flycheck-overlay)) + (should (= (overlay-start overlay) (car region))) + (should (= (overlay-end overlay) (cdr region))) + (should (eq (overlay-get overlay 'face) face)) + (should (equal (get-char-property 0 'display + (overlay-get overlay 'before-string)) + fringe-icon)) + (should (eq (overlay-get overlay 'category) category)) + (should (equal (flycheck-error-without-group (overlay-get overlay + 'flycheck-error)) + (flycheck-error-without-group error))))) + +(defun flycheck-ert-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-in-buffer (&rest errors) + "Test a syntax check in BUFFER, expecting ERRORS. + +This is like `flycheck-ert-should-syntax-check', but with a +buffer in the right mode instead of a file." + ;; Load safe file-local variables because some tests depend on them + (let ((enable-local-variables :safe) + ;; Disable all hooks at this place, to prevent 3rd party packages + ;; from interfering + (hack-local-variables-hook)) + (hack-local-variables)) + ;; Configure config file locating for unit tests + (let ((process-hook-called 0) + (suspicious nil)) + (add-hook 'flycheck-process-error-functions + (lambda (_err) + (setq process-hook-called (1+ process-hook-called)) + nil) + nil :local) + (add-hook 'flycheck-status-changed-functions + (lambda (status) + (when (eq status 'suspicious) + (setq suspicious t))) + nil :local) + (flycheck-ert-buffer-sync) + (when suspicious + (signal 'flycheck-ert-suspicious-checker nil)) + (apply #'flycheck-ert-should-errors errors) + (should (= process-hook-called (length errors)))) + (flycheck-ert-ensure-clear)) + +(defun flycheck-ert-should-syntax-check (resource-file modes &rest errors) + "Test a syntax check in RESOURCE-FILE with MODES. + +RESOURCE-FILE is the file to check. MODES is a single major mode +symbol or a list thereof, specifying the major modes to syntax +check with. If more than one major mode is specified, the test +is run for each mode separately, so if you give three major +modes, the entire test will run three times. ERRORS is the list +of expected errors, as in `flycheck-ert-should-errors'. If +omitted, the syntax check must not emit any errors. The errors +are cleared after each test. + +The syntax checker is selected via standard syntax checker +selection. To test a specific checker, you need to set +`flycheck-checker' or `flycheck-disabled-checkers' accordingly +before using this predicate, depending on whether you want to use +manual or automatic checker selection. + +During the syntax check, configuration files of syntax checkers +are also searched in the `config-files' sub-directory of the +resource directory." + (when (symbolp modes) + (setq modes (list modes))) + (dolist (mode modes) + (unless (fboundp mode) + (ert-skip (format "%S missing" mode))) + (flycheck-ert-with-resource-buffer resource-file + (funcall mode) + (apply #'flycheck-ert-should-syntax-check-in-buffer errors)))) + +(defun flycheck-ert-at-nth-error (n) + "Determine whether point is at the N'th Flycheck error. + +Return non-nil if the point is at the N'th Flycheck error in the +current buffer. Otherwise return nil." + (let* ((error (nth (1- n) flycheck-current-errors)) + (mode flycheck-highlighting-mode) + (region (flycheck-error-region-for-mode error mode))) + (and (member error (flycheck-overlay-errors-at (point))) + (= (point) (car region))))) + +(defun flycheck-ert-explain--at-nth-error (n) + "Explain a failed at-nth-error predicate at N." + (let ((errors (flycheck-overlay-errors-at (point)))) + (if (null errors) + (format "Expected to be at error %s, but no error at point %s" + n (point)) + (let ((pos (cl-position (car errors) flycheck-current-errors))) + (format "Expected to be at 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-20200405.2310/flycheck-ert.elc b/elpa/flycheck-20200405.2310/flycheck-ert.elc new file mode 100644 index 0000000000000000000000000000000000000000..3034725e8136691c9e3c3163510460bca35612ee GIT binary patch literal 24583 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 literal 0 HcmV?d00001 diff --git a/elpa/flycheck-20200405.2310/flycheck-pkg.el b/elpa/flycheck-20200405.2310/flycheck-pkg.el new file mode 100644 index 00000000..bbeff654 --- /dev/null +++ b/elpa/flycheck-20200405.2310/flycheck-pkg.el @@ -0,0 +1,16 @@ +(define-package "flycheck" "20200405.2310" "On-the-fly syntax checking" + '((dash "2.12.1") + (pkg-info "0.4") + (let-alist "1.0.4") + (seq "1.11") + (emacs "24.3")) + :keywords + '("convenience" "languages" "tools") + :authors + '(("Sebastian Wiesner" . "swiesner@lunaryorn.com")) + :maintainer + '("Clément Pit-Claudel" . "clement.pitclaudel@live.com") + :url "http://www.flycheck.org") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/flycheck-20200405.2310/flycheck.el b/elpa/flycheck-20200405.2310/flycheck.el new file mode 100644 index 00000000..1e1d2b0a --- /dev/null +++ b/elpa/flycheck-20200405.2310/flycheck.el @@ -0,0 +1,11791 @@ +;;; flycheck.el --- On-the-fly syntax checking -*- lexical-binding: t; -*- + +;; Copyright (C) 2017-2019 Flycheck contributors +;; Copyright (C) 2012-2016 Sebastian Wiesner and Flycheck contributors +;; Copyright (C) 2013, 2014 Free Software Foundation, Inc. +;; +;; Author: Sebastian Wiesner +;; Maintainer: Clément Pit-Claudel +;; fmdkdd +;; URL: http://www.flycheck.org +;; Keywords: convenience, languages, tools +;; Version: 32-cvs +;; Package-Requires: ((dash "2.12.1") (pkg-info "0.4") (let-alist "1.0.4") (seq "1.11") (emacs "24.3")) + +;; This file is not part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; On-the-fly syntax checking for GNU Emacs 24. +;; +;; Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs, +;; intended as replacement for the older Flymake extension which is part of GNU +;; Emacs. +;; +;; Flycheck automatically checks buffers for errors while you type, and reports +;; warnings and errors directly in the buffer and in an optional IDE-like error +;; list. +;; +;; It comes with a rich interface for custom syntax checkers and other +;; extensions, and has already many 3rd party extensions adding new features. +;; +;; Please read the online manual at http://www.flycheck.org for more +;; information. You can open the manual directly from Emacs with `M-x +;; flycheck-manual'. +;; +;; # Setup +;; +;; Flycheck works best on Unix systems. It does not officially support Windows, +;; but tries to maintain Windows compatibility and should generally work fine on +;; Windows, too. +;; +;; To enable Flycheck add the following to your init file: +;; +;; (add-hook 'after-init-hook #'global-flycheck-mode) +;; +;; Flycheck will then automatically check buffers in supported languages, as +;; long as all necessary tools are present. Use `flycheck-verify-setup' to +;; troubleshoot your Flycheck setup. + +;;; Code: + +(eval-when-compile + (require 'let-alist) ; `let-alist' + (require 'compile) ; Compile Mode integration + (require 'jka-compr) ; To inhibit compression of temp files + (require 'pcase) ; `pcase-dolist' (`pcase' itself is autoloaded) + ) + +(require 'dash) + +(require 'seq) ; Sequence functions +(require 'subr-x nil 'no-error) ; Additional utilities, Emacs 24.4 and upwards +(require 'cl-lib) ; `cl-defstruct' and CL utilities +(require 'tabulated-list) ; To list errors +(require 'easymenu) ; Flycheck Mode menu definition +(require 'rx) ; Regexp fanciness in `flycheck-define-checker' +(require 'help-mode) ; `define-button-type' +(require 'find-func) ; `find-function-regexp-alist' +(require 'json) ; `flycheck-parse-tslint' +(require 'ansi-color) ; `flycheck-parse-with-patterns-without-color' + + +;; Declare a bunch of dynamic variables that we need from other modes +(defvar sh-shell) ; For shell script checker predicates +(defvar ess-language) ; For r-lintr predicate + +;; 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 + awk-gawk + bazel-buildifier + c/c++-clang + c/c++-gcc + c/c++-cppcheck + cfengine + chef-foodcritic + coffee + coffee-coffeelint + coq + css-csslint + css-stylelint + cuda-nvcc + cwl + d-dmd + dockerfile-hadolint + elixir-credo + emacs-lisp + emacs-lisp-checkdoc + ember-template + erlang-rebar3 + erlang + eruby-erubis + eruby-ruumba + fortran-gfortran + go-gofmt + go-golint + go-vet + go-build + go-test + go-errcheck + go-unconvert + go-staticcheck + groovy + haml + handlebars + haskell-stack-ghc + haskell-ghc + haskell-hlint + html-tidy + javascript-eslint + javascript-jshint + javascript-standard + json-jsonlint + json-python-json + json-jq + jsonnet + less + less-stylelint + llvm-llc + lua-luacheck + lua + markdown-markdownlint-cli + markdown-mdl + nix + nix-linter + opam + perl + perl-perlcritic + php + php-phpmd + php-phpcs + processing + proselint + protobuf-protoc + protobuf-prototool + pug + puppet-parser + puppet-lint + python-flake8 + python-pylint + python-pycompile + python-mypy + r-lintr + racket + rpm-rpmlint + rst-sphinx + rst + ruby-rubocop + ruby-standard + ruby-reek + ruby-rubylint + ruby + ruby-jruby + rust-cargo + rust + rust-clippy + scala + scala-scalastyle + scheme-chicken + scss-lint + scss-stylelint + sass/scss-sass-lint + sass + scss + sh-bash + sh-posix-dash + sh-posix-bash + sh-zsh + sh-shellcheck + slim + slim-lint + sql-sqlint + systemd-analyze + tcl-nagelfar + terraform + terraform-tflint + tex-chktex + tex-lacheck + texinfo + textlint + typescript-tslint + verilog-verilator + vhdl-ghdl + xml-xmlstarlet + xml-xmllint + yaml-jsyaml + yaml-ruby + yaml-yamllint) + "Syntax checkers available for automatic selection. + +A list of Flycheck syntax checkers to choose from when syntax +checking a buffer. Flycheck will automatically select a suitable +syntax checker from this list, unless `flycheck-checker' is set, +either directly or with `flycheck-select-checker'. + +You should not need to change this variable normally. In order +to disable syntax checkers, please use +`flycheck-disabled-checkers'. This variable is intended for 3rd +party extensions to tell Flycheck about new syntax checkers. + +Syntax checkers in this list must be defined with +`flycheck-define-checker'." + :group 'flycheck + :type '(repeat (symbol :tag "Checker")) + :risky t) + +(defcustom flycheck-disabled-checkers nil + "Syntax checkers excluded from automatic selection. + +A list of Flycheck syntax checkers to exclude from automatic +selection. Flycheck will never automatically select a syntax +checker in this list, regardless of the value of +`flycheck-checkers'. + +However, syntax checkers in this list are still available for +manual selection with `flycheck-select-checker'. + +Use this variable to disable syntax checkers, instead of removing +the syntax checkers from `flycheck-checkers'. You may also use +this option as a file or directory local variable to disable +specific checkers in individual files and directories +respectively." + :group 'flycheck + :type '(repeat (symbol :tag "Checker")) + :package-version '(flycheck . "0.16") + :safe #'flycheck-symbol-list-p) +(make-variable-buffer-local 'flycheck-disabled-checkers) + +(defvar-local flycheck--automatically-disabled-checkers nil + "List of syntax checkers automatically disabled for this buffer. + +A checker can be automatically disabled in two cases: + +1. Its `:enabled' predicate returned false. +2. It returned too many errors (see `flycheck-checker-error-threshold'). + +To trigger a reverification from Emacs Lisp code, do not modify +this variable: use `flycheck-reset-enabled-checker'.") + +(defvar-local flycheck-checker nil + "Syntax checker to use for the current buffer. + +If unset or nil, automatically select a suitable syntax checker +from `flycheck-checkers' on every syntax check. + +If set to a syntax checker only use this syntax checker and never +select one from `flycheck-checkers' automatically. The syntax +checker is used regardless of whether it is contained in +`flycheck-checkers' or `flycheck-disabled-checkers'. If the +syntax checker is unusable in the current buffer an error is +signaled. + +A syntax checker assigned to this variable must be defined with +`flycheck-define-checker'. + +Use the command `flycheck-select-checker' to select a syntax +checker for the current buffer, or set this variable as file +local variable to always use a specific syntax checker for a +file. See Info Node `(emacs)Specifying File Variables' for more +information about file variables.") +(put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p) + +(defcustom flycheck-locate-config-file-functions nil + "Functions to locate syntax checker configuration files. + +Each function in this hook must accept two arguments: The value +of the configuration file variable, and the syntax checker +symbol. It must return either a string with an absolute path to +the configuration file, or nil, if it cannot locate the +configuration file. + +The functions in this hook are called in order of appearance, until a +function returns non-nil. The configuration file returned by that +function is then given to the syntax checker if it exists. + +This variable is an abnormal hook. See Info +node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :risky t) + +(defcustom flycheck-checker-error-threshold 400 + "Maximum errors allowed per syntax checker. + +The value of this variable is either an integer denoting the +maximum number of errors per syntax checker and buffer, or nil to +not limit the errors reported from a syntax checker. + +If this variable is a number and a syntax checker reports more +errors than the value of this variable, its errors are not +discarded, and not highlighted in the buffer or available in the +error list. The affected syntax checker is also disabled for +future syntax checks of the buffer." + :group 'flycheck + :type '(choice (const :tag "Do not limit reported errors" nil) + (integer :tag "Maximum number of errors")) + :risky t + :package-version '(flycheck . "0.22")) + +(defcustom flycheck-process-error-functions nil + "Functions to process errors. + +Each function in this hook must accept a single argument: A +Flycheck error to process. + +All functions in this hook are called in order of appearance, +until a function returns non-nil. Thus, a function in this hook +may return nil, to allow for further processing of the error, or +any non-nil value, to indicate that the error was fully processed +and inhibit any further processing. + +The functions are called for each newly parsed error immediately +after the corresponding syntax checker finished. At this stage, +the overlays from the previous syntax checks are still present, +and there may be further syntax checkers in the chain. + +This variable is an abnormal hook. See Info +node `(elisp)Hooks'." + :group 'flycheck + :type 'hook + :package-version '(flycheck . "0.13") + :risky t) + +(defcustom flycheck-display-errors-delay 0.9 + "Delay in seconds before displaying errors at point. + +Use floating point numbers to express fractions of seconds." + :group 'flycheck + :type 'number + :package-version '(flycheck . "0.15") + :safe #'numberp) + +(defcustom flycheck-display-errors-function #'flycheck-display-error-messages + "Function to display error messages. + +If set to a function, call the function with the list of errors +to display as single argument. Each error is an instance of the +`flycheck-error' struct. + +If set to nil, do not display errors at all." + :group 'flycheck + :type '(choice (const :tag "Display error messages" + flycheck-display-error-messages) + (const :tag "Display error messages only if no error list" + flycheck-display-error-messages-unless-error-list) + (function :tag "Error display function")) + :package-version '(flycheck . "0.13") + :risky t) + +(defcustom flycheck-help-echo-function #'flycheck-help-echo-all-error-messages + "Function to compute the contents of the error tooltips. + +If set to a function, call the function with the list of errors +to display as single argument. Each error is an instance of the +`flycheck-error' struct. The function is used to set the +help-echo property of flycheck error overlays. It should return +a string, which is displayed when the user hovers over an error +or presses \\[display-local-help]. + +If set to nil, do not show error tooltips." + :group 'flycheck + :type '(choice (const :tag "Concatenate error messages to form a tooltip" + flycheck-help-echo-all-error-messages) + (function :tag "Help echo function")) + :package-version '(flycheck . "0.25") + :risky t) + +(defcustom flycheck-command-wrapper-function #'identity + "Function to modify checker commands before execution. + +The value of this option is a function which is given a list +containing the full command of a syntax checker after +substitution through `flycheck-substitute-argument' but before +execution. The function may return a new command for Flycheck to +execute. + +The default value is `identity' which does not change the +command. You may provide your own function to run Flycheck +commands through `bundle exec', `nix-shell' or similar wrappers." + :group 'flycheck + :type '(choice (const :tag "Do not modify commands" identity) + (function :tag "Modify command with a custom function")) + :package-version '(flycheck . "0.25") + :risky t) + +(defcustom flycheck-executable-find #'flycheck-default-executable-find + "Function to search for executables. + +The value of this option is a function which is given the name or +path of an executable and shall return the full path to the +executable, or nil if the executable does not exit. + +The default is `flycheck-default-executable-find', which searches +variable `exec-path' when given a command name, and resolves +paths to absolute ones. You can customize this option to search +for checkers in other environments such as bundle or NixOS +sandboxes." + :group 'flycheck + :type '(choice + (const :tag "Search executables in `exec-path'" + flycheck-default-executable-find) + (function :tag "Search executables with a custom function")) + :package-version '(flycheck . "32") + :risky t) + +(defun flycheck-default-executable-find (executable) + "Resolve EXECUTABLE to a full path. + +Like `executable-find', but supports relative paths. + +Attempts invoking `executable-find' first; if that returns nil, +and EXECUTABLE contains a directory component, expands to a full +path and tries invoking `executable-find' again." + ;; file-name-directory returns non-nil iff the given path has a + ;; directory component. + (or + (executable-find executable) + (when (file-name-directory executable) + (executable-find (expand-file-name executable))))) + +(defcustom flycheck-indication-mode 'left-fringe + "The indication mode for Flycheck errors 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 when a checker only reports the starting position of an +error. The following modes are known: + +`columns' + Highlight a single character. If the error does not have a column, + highlight the whole line. + +`symbols' + Highlight a full symbol if there is any, otherwise behave like `columns'. + This is the default. + +`sexps' + Highlight a full expression, if there is any, otherwise behave like + `columns'. Note that this mode can be *very* slow in some major modes. + +`lines' + Highlight the whole line. + +nil + Do not highlight errors at all. However, errors will still + be reported in the mode line and in error message popups, + and indicated according to `flycheck-indication-mode'." + :group 'flycheck + :type '(choice (const :tag "Highlight columns only" columns) + (const :tag "Highlight symbols" symbols) + (const :tag "Highlight expressions" sexps) + (const :tag "Highlight whole lines" lines) + (const :tag "Do not highlight errors" nil)) + :package-version '(flycheck . "0.14") + :safe #'symbolp) + +(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 they added them before Flycheck was loaded. +(dolist (hook (list #'flycheck-locate-config-file-by-path + #'flycheck-locate-config-file-ancestor-directories + #'flycheck-locate-config-file-home)) + (add-hook 'flycheck-locate-config-file-functions hook 'append)) + +(add-hook 'flycheck-process-error-functions #'flycheck-add-overlay 'append) + + +;;; Global Flycheck menu +(defvar flycheck-mode-menu-map + (easy-menu-create-menu + "Syntax Checking" + '(["Enable on-the-fly syntax checking" flycheck-mode + :style toggle :selected flycheck-mode + :enable (or flycheck-mode + ;; Don't let users toggle the mode if there is no syntax + ;; checker for this buffer + (seq-find #'flycheck-checker-supports-major-mode-p + flycheck-checkers))] + ["Check current buffer" flycheck-buffer flycheck-mode] + ["Clear errors in buffer" flycheck-clear t] + "---" + ["Go to next error" flycheck-next-error flycheck-mode] + ["Go to previous error" flycheck-previous-error flycheck-mode] + ["Show all errors" flycheck-list-errors flycheck-mode] + "---" + ["Copy messages at point" flycheck-copy-errors-as-kill + (flycheck-overlays-at (point))] + ["Explain error at point" flycheck-explain-error-at-point] + "---" + ["Select syntax checker" flycheck-select-checker flycheck-mode] + ["Disable syntax checker" flycheck-disable-checker flycheck-mode] + ["Set executable of syntax checker" flycheck-set-checker-executable + flycheck-mode] + "---" + ["Describe syntax checker" flycheck-describe-checker t] + ["Verify setup" flycheck-verify-setup t] + ["Show Flycheck version" flycheck-version t] + ["Read the Flycheck manual" flycheck-info t])) + "Menu of command `flycheck-mode'.") + +(easy-menu-add-item nil '("Tools") flycheck-mode-menu-map "Spell Checking") + + +;;; Version information, manual and loading of Flycheck +(defun flycheck-version (&optional show-version) + "Get the Flycheck version as string. + +If called interactively or if SHOW-VERSION is non-nil, show the +version in the echo area and the messages buffer. + +The returned string includes both, the version from package.el +and the library version, if both a present and different. + +If the version number could not be determined, signal an error, +if called interactively, or if SHOW-VERSION is non-nil, otherwise +just return nil." + (interactive (list t)) + (let ((version (pkg-info-version-info 'flycheck))) + (when show-version + (message "Flycheck version: %s" version)) + version)) + +(defun flycheck-unload-function () + "Unload function for Flycheck." + (global-flycheck-mode -1) + (easy-menu-remove-item nil '("Tools") (cadr flycheck-mode-menu-map)) + (remove-hook 'kill-emacs-hook #'flycheck-global-teardown) + (setq find-function-regexp-alist + (assq-delete-all 'flycheck-checker find-function-regexp-alist))) + +;;;###autoload +(defun flycheck-manual () + "Open the Flycheck manual." + (interactive) + (browse-url "http://www.flycheck.org")) + +(define-obsolete-function-alias 'flycheck-info + 'flycheck-manual "26" "Open the Flycheck manual.") + + +;;; Utility functions +(defun flycheck-sexp-to-string (sexp) + "Convert SEXP to a string. + +Like `prin1-to-string' but ensure that the returned string +is loadable." + (let ((print-quoted t) + (print-length nil) + (print-level nil)) + (prin1-to-string sexp))) + +(defun flycheck-string-to-number-safe (string) + "Safely convert STRING to a number. + +If STRING is of string type and a numeric string, convert STRING +to a number and return it. Otherwise return nil." + (let ((number-re (rx string-start (one-or-more (any digit)) string-end))) + (when (and (stringp string) (string-match-p number-re string)) + (string-to-number string)))) + +(defun flycheck-string-or-nil-p (obj) + "Determine if OBJ is a string or nil." + (or (null obj) (stringp obj))) + +(defun flycheck-string-list-p (obj) + "Determine if OBJ is a list of strings." + (and (listp obj) (seq-every-p #'stringp obj))) + +(defun flycheck-string-or-string-list-p (obj) + "Determine if OBJ is a string or a list of strings." + (or (stringp obj) (flycheck-string-list-p obj))) + +(defun flycheck-symbol-list-p (obj) + "Determine if OBJ is a list of symbols." + (and (listp obj) (seq-every-p #'symbolp obj))) + +(defvar-local flycheck--file-truename-cache nil) + +(defun flycheck--file-truename (file) + "Memoize the result of `file-truename' on (directory-file-name FILE)." + ;; `file-truename' is slow, but alternatives are incomplete, so memoizing is + ;; our best bet. See https://github.com/flycheck/flycheck/pull/1698. + (unless flycheck--file-truename-cache + (setq-local flycheck--file-truename-cache (make-hash-table :test 'equal))) + (or (gethash file flycheck--file-truename-cache) + (puthash file (file-truename (directory-file-name file)) + flycheck--file-truename-cache))) + +(defun flycheck-same-files-p (file-a file-b) + "Determine whether FILE-A and FILE-B refer to the same file. + +Files are the same if (in the order checked) they are equal, or +if they resolve to the same canonical paths." + (or (string= file-a file-b) + (string= (flycheck--file-truename file-a) + (flycheck--file-truename file-b)))) + +(defvar-local flycheck-temporaries nil + "Temporary files and directories created by Flycheck.") + +(defun flycheck-temp-dir-system () + "Create a unique temporary directory. + +Use `flycheck-temp-prefix' as prefix, and add the directory to +`flycheck-temporaries'. + +Return the path of the directory" + (let* ((tempdir (make-temp-file flycheck-temp-prefix 'directory))) + (push tempdir flycheck-temporaries) + tempdir)) + +(defun flycheck-temp-file-system (filename &optional suffix) + "Create a temporary file named after FILENAME. + +If FILENAME is non-nil, this function creates a temporary +directory with `flycheck-temp-dir-system', and creates a file +with the same name as FILENAME in this directory. + +Otherwise this function creates a temporary file starting with +`flycheck-temp-prefix'. If present, SUFFIX is appended; +otherwise, a random suffix is used. The path of the file is +added to `flycheck-temporaries'. + +Return the path of the file." + (let ((tempfile (convert-standard-filename + (if filename + (expand-file-name (file-name-nondirectory filename) + (flycheck-temp-dir-system)) + (make-temp-file flycheck-temp-prefix nil suffix))))) + (push tempfile flycheck-temporaries) + tempfile)) + +(defun flycheck-temp-file-inplace (filename &optional suffix) + "Create an in-place copy of FILENAME. + +Prefix the file with `flycheck-temp-prefix' and add the path of +the file to `flycheck-temporaries'. + +If FILENAME is nil, fall back to `flycheck-temp-file-system' with +the specified SUFFIX. + +Return the path of the file." + (if filename + (let* ((tempname (format "%s_%s" + flycheck-temp-prefix + (file-name-nondirectory filename))) + (tempfile (convert-standard-filename + (expand-file-name tempname + (file-name-directory filename))))) + (push tempfile flycheck-temporaries) + tempfile) + (flycheck-temp-file-system filename suffix))) + +(defun flycheck-temp-directory (checker) + "Return the directory where CHECKER writes temporary files. + +Return nil if the CHECKER does not write temporary files." + (let ((args (flycheck-checker-arguments checker))) + (cond + ((memq 'source args) temporary-file-directory) + ((memq 'source-inplace args) + (if buffer-file-name (file-name-directory buffer-file-name) + temporary-file-directory)) + (t nil)))) + +(defun flycheck-temp-files-writable-p (checker) + "Whether CHECKER can write temporary files. + +If CHECKER has `source' or `source-inplace' in its `:command', +return whether flycheck has the permissions to create the +respective temporary files. + +Return t if CHECKER does not use temporary files." + (let ((dir (flycheck-temp-directory checker))) + (or (not dir) (file-writable-p dir)))) + +(defun flycheck-save-buffer-to-file (file-name) + "Save the contents of the current buffer to FILE-NAME." + (make-directory (file-name-directory file-name) t) + (let ((jka-compr-inhibit t)) + (write-region nil nil file-name nil 0))) + +(defun flycheck-save-buffer-to-temp (temp-file-fn) + "Save buffer to temp file returned by TEMP-FILE-FN. + +Return the name of the temporary file." + (let ((filename (funcall temp-file-fn (buffer-file-name)))) + ;; Do not flush short-lived temporary files onto disk + (let ((write-region-inhibit-fsync t)) + (flycheck-save-buffer-to-file filename)) + filename)) + +(defun flycheck-prepend-with-option (option items &optional prepend-fn) + "Prepend OPTION to each item in ITEMS, using PREPEND-FN. + +Prepend OPTION to each item in ITEMS. + +ITEMS is a list of strings to pass to the syntax checker. OPTION +is the option, as string. PREPEND-FN is a function called to +prepend OPTION to each item in ITEMS. It receives the option and +a single item from ITEMS as argument, and must return a string or +a list of strings with OPTION prepended to the item. If +PREPEND-FN is nil or omitted, use `list'. + +Return a list of strings where OPTION is prepended to each item +in ITEMS using PREPEND-FN. If PREPEND-FN returns a list, it is +spliced into the resulting list." + (unless (stringp option) + (error "Option %S is not a string" option)) + (unless prepend-fn + (setq prepend-fn #'list)) + (let ((prepend + (lambda (item) + (let ((result (funcall prepend-fn option item))) + (cond + ((and (listp result) (seq-every-p #'stringp result)) result) + ((stringp result) (list result)) + (t (error "Invalid result type for option: %S" result))))))) + (apply #'append (seq-map prepend items)))) + +(defun flycheck-find-in-buffer (pattern) + "Find PATTERN in the current buffer. + +Return the result of the first matching group of PATTERN, or nil, +if PATTERN did not match." + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (when (re-search-forward pattern nil 'no-error) + (match-string-no-properties 1))))) + +(defun flycheck-buffer-empty-p (&optional buffer) + "Check whether a BUFFER is empty, defaulting to the current one." + (= (buffer-size buffer) 0)) + +(defun flycheck-buffer-nonempty-p (&optional buffer) + "Check whether a BUFFER is nonempty, defaulting to the current one." + (> (buffer-size buffer) 0)) + +(defun flycheck-ephemeral-buffer-p () + "Determine whether the current buffer is an ephemeral buffer. + +See Info node `(elisp)Buffer Names' for information about +ephemeral buffers." + (string-prefix-p " " (buffer-name))) + +(defun flycheck-encrypted-buffer-p () + "Determine whether the current buffer is an encrypted file. + +See Info node `(epa)Top' for Emacs' interface to encrypted +files." + ;; The EPA file handler sets this variable locally to remember the recipients + ;; of the encrypted file for re-encryption. Hence, a local binding of this + ;; variable is a good indication that the buffer is encrypted. I haven't + ;; found any better indicator anyway. + (local-variable-p 'epa-file-encrypt-to)) + +(defun flycheck-autoloads-file-p () + "Determine whether the current buffer is an autoloads file. + +Autoloads are generated by package.el during installation." + (string-suffix-p "-autoloads.el" (buffer-name))) + +(defun flycheck-in-user-emacs-directory-p (filename) + "Whether FILENAME is in `user-emacs-directory'." + (string-prefix-p (file-name-as-directory + (flycheck--file-truename user-emacs-directory)) + (flycheck--file-truename filename))) + +(defun flycheck-safe-delete (file-or-dir) + "Safely delete FILE-OR-DIR." + (ignore-errors + (if (file-directory-p file-or-dir) + (delete-directory file-or-dir 'recursive) + (delete-file file-or-dir)))) + +(defun flycheck-safe-delete-temporaries () + "Safely delete all temp files and directories of Flycheck. + +Safely delete all files and directories listed in +`flycheck-temporaries' and set the variable's value to nil." + (seq-do #'flycheck-safe-delete flycheck-temporaries) + (setq flycheck-temporaries nil)) + +(defun flycheck-rx-file-name (form) + "Translate the `(file-name)' FORM into a regular expression." + (let ((body (or (cdr form) '((minimal-match + (one-or-more not-newline)))))) + (rx-to-string `(group-n 1 ,@body) t))) + +(defun flycheck-rx-message (form) + "Translate the `(message)' FORM into a regular expression." + (let ((body (or (cdr form) '((one-or-more not-newline))))) + (rx-to-string `(group-n 4 ,@body) t))) + +(defun flycheck-rx-id (form) + "Translate the `(id)' FORM into a regular expression." + (rx-to-string `(group-n 5 ,@(cdr form)) t)) + +(defun flycheck-rx-to-string (form &optional no-group) + "Like `rx-to-string' for FORM, but with special keywords: + +`line' + matches the initial line number. + +`column' + matches the initial column number. + +`end-line' + matches the final line number. + +`end-column' + matches the final column number (exclusive). + + +`(file-name SEXP ...)' + matches the file name. SEXP describes the file name. If no + SEXP is given, use a default body of `(minimal-match + (one-or-more not-newline))'. + +`(message SEXP ...)' + matches the message. SEXP constitutes the body of the + message. If no SEXP is given, use a default body + of `(one-or-more not-newline)'. + +`(id SEXP ...)' + matches an error ID. SEXP describes the ID. + +NO-GROUP is passed to `rx-to-string'. + +See `rx' for a complete list of all built-in `rx' forms." + (let ((rx-constituents + (append + `((file-name flycheck-rx-file-name 0 nil) ;; group 1 + (line . ,(rx (group-n 2 (one-or-more digit)))) + (column . ,(rx (group-n 3 (one-or-more digit)))) + (message flycheck-rx-message 0 nil) ;; group 4 + (id flycheck-rx-id 0 nil) ;; group 5 + (end-line . ,(rx (group-n 6 (one-or-more digit)))) + (end-column . ,(rx (group-n 7 (one-or-more digit))))) + rx-constituents nil))) + (rx-to-string form no-group))) + +(defun flycheck-current-load-file () + "Get the source file currently being loaded. + +Always return the name of the corresponding source file, never +any byte-compiled file. + +Return nil, if the currently loaded file cannot be determined." + (-when-let* ((this-file (cond + (load-in-progress load-file-name) + ((bound-and-true-p byte-compile-current-file)) + (t (buffer-file-name)))) + ;; A best guess for the source file of a compiled library. Works + ;; well in most cases, and especially for ELPA packages + (source-file (concat (file-name-sans-extension this-file) + ".el"))) + (when (file-exists-p source-file) + source-file))) + +(defun flycheck-module-root-directory (module &optional file-name) + "Get the root directory for a MODULE in FILE-NAME. + +MODULE is a qualified module name, either a string with +components separated by a dot, or as list of components. +FILE-NAME is the name of the file or directory containing the +module as string. When nil or omitted, defaults to the return +value of function `buffer-file-name'. + +Return the root directory of the module, that is, the directory, +from which FILE-NAME can be reached by descending directories +along each part of MODULE. + +If the MODULE name does not match the directory hierarchy upwards +from FILE-NAME, return the directory containing FILE-NAME. When +FILE-NAME is nil, return `default-directory'." + (let ((file-name (or file-name (buffer-file-name))) + (module-components (if (stringp module) + (split-string module (rx ".")) + (copy-sequence module)))) + (if (and module-components file-name) + (let ((parts (nreverse module-components)) + (base-directory (directory-file-name + (file-name-sans-extension file-name)))) + (while (and parts + (string= (file-name-nondirectory base-directory) + (car parts))) + (pop parts) + (setq base-directory (directory-file-name + (file-name-directory base-directory)))) + (file-name-as-directory base-directory)) + (if file-name + (file-name-directory file-name) + (expand-file-name default-directory))))) + +(defun flycheck-goto-line (line) + "Move point to beginning of line number LINE." + (goto-char (point-min)) + (forward-line (- line 1))) + +(defun flycheck-line-column-to-position (line column) + "Return the point closest to LINE, COLUMN on line LINE. + +COLUMN is one-based." + (save-excursion + (flycheck-goto-line line) + (min (+ (point) (1- column)) (line-end-position)))) + +(defun flycheck-line-column-at-point () + "Return the line and column number at point." + (cons (line-number-at-pos) (1+ (- (point) (line-beginning-position))))) + +(defun flycheck-line-column-at-pos (pos) + "Return the line and column number at position POS. + +COLUMN is one-based." + (let ((inhibit-field-text-motion t)) + (save-excursion + (goto-char pos) + (flycheck-line-column-at-point)))) + + +;;; Minibuffer tools +(defvar flycheck-read-checker-history nil + "`completing-read' history of `flycheck-read-checker'.") + +(defun flycheck-completing-read (prompt candidates default &optional history) + "Read a value from the minibuffer. + +Use `flycheck-completing-read-function' to read input from the +minibuffer with completion. + +Show PROMPT and read one of CANDIDATES, defaulting to DEFAULT. +HISTORY is passed to `flycheck-completing-read-function'. + +Note that `flycheck-completing-read-function' may return an empty +string instead of nil, even when \"\" isn't among the candidates. +See `completing-read' for more details." + (funcall flycheck-completing-read-function + prompt candidates nil 'require-match nil history default)) + +(defun flycheck-read-checker (prompt &optional default property candidates) + "Read a flycheck checker from minibuffer with PROMPT and DEFAULT. + +PROMPT is a string to show in the minibuffer as prompt. It +should end with a single space. DEFAULT is a symbol denoting the +default checker to use, if the user did not select any checker. +PROPERTY is a symbol denoting a syntax checker property. If +non-nil, only complete syntax checkers which have a non-nil value +for PROPERTY. CANDIDATES is an optional list of all syntax +checkers available for completion, defaulting to all defined +checkers. If given, PROPERTY is ignored. + +Return the checker as symbol, or DEFAULT if no checker was +chosen. If DEFAULT is nil and no checker was chosen, signal a +`user-error' if the underlying completion system does not provide +a default on its own." + (when (and default (not (flycheck-valid-checker-p default))) + (error "%S is no valid Flycheck checker" default)) + (let* ((candidates (seq-map #'symbol-name + (or candidates + (flycheck-defined-checkers property)))) + (default (and default (symbol-name default))) + (input (flycheck-completing-read + prompt candidates default + 'flycheck-read-checker-history))) + (when (string-empty-p input) + (unless default + (user-error "No syntax checker selected")) + (setq input default)) + (let ((checker (intern input))) + (unless (flycheck-valid-checker-p checker) + (error "%S is not a valid Flycheck syntax checker" checker)) + checker))) + +(defun flycheck-read-error-level (prompt) + "Read an error level from the user with PROMPT. + +Only offers level for which errors currently exist, in addition +to the default levels." + (let* ((levels (seq-map #'flycheck-error-level + (flycheck-error-list-current-errors))) + (levels-with-defaults (append '(info warning error) levels)) + (uniq-levels (seq-uniq levels-with-defaults)) + (level (flycheck-completing-read prompt uniq-levels nil))) + (when (string-empty-p level) (setq level nil)) + (and level (intern level)))) + + +;;; Checker API +(defun flycheck-defined-checkers (&optional property) + "Find all defined syntax checkers, optionally with PROPERTY. + +PROPERTY is a symbol. If given, only return syntax checkers with +a non-nil value for PROPERTY. + +The returned list is sorted alphapetically by the symbol name of +the syntax checkers." + (let (defined-checkers) + (mapatoms (lambda (symbol) + (when (and (flycheck-valid-checker-p symbol) + (or (null property) + (flycheck-checker-get symbol property))) + (push symbol defined-checkers)))) + (sort defined-checkers #'string<))) + +(defun flycheck-registered-checker-p (checker) + "Determine whether CHECKER is registered. + +A checker is registered if it is contained in +`flycheck-checkers'." + (and (flycheck-valid-checker-p checker) + (memq checker flycheck-checkers))) + +(defun flycheck-disabled-checker-p (checker) + "Determine whether CHECKER is disabled. + +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 + (or "flycheck-define-checker" "flycheck-define-command-checker") + symbol-end + (eval (list 'regexp find-function-space-re)) + (? "'") + symbol-start "%s" symbol-end + (or (syntax whitespace) line-end)) + "Regular expression to find a checker definition.") + +(add-to-list 'find-function-regexp-alist + '(flycheck-checker . flycheck-find-checker-regexp)) + +(defun flycheck-goto-checker-definition (checker file) + "Go to to the definition of CHECKER in FILE." + (let ((location (find-function-search-for-symbol + checker 'flycheck-checker file))) + (pop-to-buffer (car location)) + (if (cdr location) + (goto-char (cdr location)) + (message "Unable to find checker location in file")))) + +(defun flycheck-checker-at-point () + "Return the Flycheck checker found at or before point. + +Return nil if there is no checker." + (let ((symbol (variable-at-point 'any-symbol))) + (when (flycheck-valid-checker-p symbol) + symbol))) + +(defun flycheck-describe-checker (checker) + "Display the documentation of CHECKER. + +CHECKER is a checker symbol. + +Pop up a help buffer with the documentation of CHECKER." + (interactive + (let* ((enable-recursive-minibuffers t) + (default (or (flycheck-checker-at-point) + (ignore-errors (flycheck-get-checker-for-buffer)))) + (prompt (if default + (format "Describe syntax checker (default %s): " default) + "Describe syntax checker: "))) + (list (flycheck-read-checker prompt default)))) + (unless (flycheck-valid-checker-p checker) + (user-error "You didn't specify a Flycheck syntax checker")) + (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-checker-symbol (next) + "Get the checker symmbol of NEXT checker. + +NEXT should be either a cons (NEXT-CHECKER . LEVEL) or a +symbol." + (if (consp next) (cdr next) next)) + +(defun flycheck-get-next-checkers (checker) + "Return the immediate next checkers of CHECKER. + +This is a list of checker symbols. The error levels of the +`:next-checker' property are ignored." + (mapcar #'flycheck--get-next-checker-symbol + (flycheck-checker-get checker 'next-checkers))) + +(defun flycheck-all-next-checkers (checker) + "Return all checkers that may follow CHECKER. + +Return the transitive closure of the next-checker relation. The +return value is a list of checkers, not including CHECKER." + (let ((next-checkers) + (visited) + (queue (list checker))) + (while queue + (let ((c (pop queue))) + (push c visited) + (dolist (n (flycheck-get-next-checkers c)) + (push n next-checkers) + (unless (memq n visited) + (cl-pushnew n queue))))) + (seq-uniq next-checkers))) + +(defun flycheck--verify-next-checkers (checker) + "Return a verification result for the next checkers of CHECKER." + (-when-let (next (flycheck-get-next-checkers checker)) + (list + (flycheck-verification-result-new + :label "next checkers" + ;; We use `make-text-button' to preserve the button properties in the + ;; string + :message (mapconcat + (lambda (checker) + (make-text-button (symbol-name checker) nil + 'type 'help-flycheck-checker-doc + 'help-args (list checker))) + next + ", "))))) + +(defun flycheck--verify-print-header (desc buffer) + "Print a title with DESC for BUFFER in the current buffer. + +DESC is an arbitrary string containing a description, and BUFFER +is the buffer being verified. The name and the major mode mode +of BUFFER are printed. + +DESC and information about BUFFER are printed in the current +buffer." + (princ desc) + (insert (propertize (buffer-name buffer) 'face 'bold)) + (princ " in ") + (let ((mode (buffer-local-value 'major-mode buffer))) + (insert-button (symbol-name mode) + 'type 'help-function + 'help-args (list mode))) + (princ ":\n\n")) + +(defun flycheck--verify-print-footer (buffer) + "Print a footer for BUFFER in the current buffer. + +BUFFER is the buffer being verified." + (princ "Flycheck Mode is ") + (let ((enabled (buffer-local-value 'flycheck-mode buffer))) + (insert (propertize (if enabled "enabled" "disabled") + 'face (if enabled 'success '(warning bold))))) + (princ + (with-current-buffer buffer + ;; Use key binding state in the verified buffer to print the help. + (substitute-command-keys + ". Use \\[universal-argument] \\[flycheck-disable-checker] \ +to enable disabled checkers."))) + (save-excursion + (let ((end (point))) + (backward-paragraph) + (fill-region-as-paragraph (point) end))) + + (princ "\n\n--------------------\n\n") + (princ (format "Flycheck version: %s\n" (flycheck-version))) + (princ (format "Emacs version: %s\n" emacs-version)) + (princ (format "System: %s\n" system-configuration)) + (princ (format "Window system: %S\n" window-system))) + +(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-remove-next-checker (checker next) + "After CHECKER remove a NEXT checker. + +CHECKER is a syntax checker symbol, from which to remove NEXT +checker. + +NEXT is a cons or a symbol, as documented in +`flycheck-add-next-checker'." + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid syntax checker" checker)) + (let* ((next-symbol (flycheck--get-next-checker-symbol next))) + (setf + (flycheck-checker-get checker 'next-checkers) + (seq-remove + (lambda (next) (eq (flycheck--get-next-checker-symbol next) next-symbol)) + (flycheck-checker-get checker 'next-checkers))))) + +(defun flycheck-add-next-checker (checker next &optional append) + "After CHECKER add a NEXT checker. + +CHECKER is a syntax checker symbol, to which to add NEXT checker. + +NEXT is a cons cell `(LEVEL . NEXT-CHECKER)'. NEXT-CHECKER is a +symbol denoting the syntax checker to run after CHECKER. LEVEL +is an error level. NEXT-CHECKER will only be used if there is no +current error whose level is more severe than LEVEL. LEVEL may +also be t, in which case NEXT-CHECKER is used regardless of the +current errors. + +NEXT can also be a syntax checker symbol only, which is +equivalent to `(t . NEXT)'. + +NEXT-CHECKER is prepended before other next checkers, unless +APPEND is non-nil." + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid syntax checker" checker)) + (flycheck-validate-next-checker next 'strict) + (flycheck-remove-next-checker checker next) + (let ((next-checkers (flycheck-checker-get checker 'next-checkers))) + (setf (flycheck-checker-get checker 'next-checkers) + (if append (append next-checkers (list next)) + (cons next next-checkers))))) + +(defun flycheck-add-mode (checker mode) + "To CHECKER add a new major MODE. + +CHECKER and MODE are symbols denoting a syntax checker and a +major mode respectively. + +Add MODE to the `:modes' property of CHECKER, so that CHECKER +will be used in buffers with MODE." + (unless (flycheck-valid-checker-p checker) + (error "%s is not a valid syntax checker" checker)) + (unless (symbolp mode) + (error "%s is not a symbol" mode)) + (push mode (flycheck-checker-get checker 'modes))) + + +;;; Generic syntax checks +(cl-defstruct (flycheck-syntax-check + (:constructor flycheck-syntax-check-new)) + "Structure for storing syntax check state. + +Slots: + +`buffer' + The buffer being checked. + +`checker' + The syntax checker being used. + +`context' + The context object. + +`working-directory' + Working directory for the syntax checker. Serve as a value for + `default-directory' for a checker." + buffer checker context working-directory) + +(defun flycheck-syntax-check-start (syntax-check callback) + "Start a SYNTAX-CHECK with CALLBACK." + (let ((checker (flycheck-syntax-check-checker syntax-check)) + (default-directory + (flycheck-syntax-check-working-directory syntax-check))) + (setf (flycheck-syntax-check-context syntax-check) + (funcall (flycheck-checker-get checker 'start) checker callback)))) + +(defun flycheck-syntax-check-interrupt (syntax-check) + "Interrupt a SYNTAX-CHECK." + (let* ((checker (flycheck-syntax-check-checker syntax-check)) + (interrupt-fn (flycheck-checker-get checker 'interrupt)) + (context (flycheck-syntax-check-context syntax-check))) + (when interrupt-fn + (funcall interrupt-fn checker context)))) + + +;;; Syntax checking mode + +(defvar flycheck-mode-map + (let ((map (make-sparse-keymap))) + (define-key map flycheck-keymap-prefix flycheck-command-map) + ;; We place the menu under a custom menu key. Since this menu key is not + ;; present in the menu of the global map, no top-level menu entry is added + ;; to the global menu bar. However, it still appears on the mode line + ;; lighter. + (define-key map [menu-bar flycheck] flycheck-mode-menu-map) + map) + "Keymap of command `flycheck-mode'.") + +(defvar-local flycheck-old-next-error-function nil + "Remember the old `next-error-function'.") + +(defconst flycheck-hooks-alist + '( + ;; Handle events that may start automatic syntax checks + (after-save-hook . flycheck-handle-save) + (after-change-functions . flycheck-handle-change) + ;; Handle events that may triggered pending deferred checks + (window-configuration-change-hook . flycheck-perform-deferred-syntax-check) + (post-command-hook . flycheck-perform-deferred-syntax-check) + ;; Teardown Flycheck whenever the buffer state is about to get lost, to + ;; clean up temporary files and directories. + (kill-buffer-hook . flycheck-teardown) + (change-major-mode-hook . flycheck-teardown) + (before-revert-hook . flycheck-teardown) + ;; Update the error list if necessary + (post-command-hook . flycheck-error-list-update-source) + (post-command-hook . flycheck-error-list-highlight-errors) + ;; Display errors. Show errors at point after commands (like movements) and + ;; when Emacs gets focus. Cancel the display timer when Emacs looses focus + ;; (as there's no need to display errors if the user can't see them), and + ;; hide the error buffer (for large error messages) if necessary. Note that + ;; the focus hooks only work on Emacs 24.4 and upwards, but since undefined + ;; hooks are perfectly ok we don't need a version guard here. They'll just + ;; not work silently. + (post-command-hook . flycheck-maybe-display-error-at-point-soon) + (focus-in-hook . flycheck-display-error-at-point-soon) + (focus-out-hook . flycheck-cancel-error-display-error-at-point-timer) + (post-command-hook . flycheck-hide-error-buffer) + ;; Immediately show error popups when navigating to an error + (next-error-hook . flycheck-display-error-at-point)) + "Hooks which Flycheck needs to hook in. + +The `car' of each pair is a hook variable, the `cdr' a function +to be added or removed from the hook variable if Flycheck mode is +enabled and disabled respectively.") + +;;;###autoload +(define-minor-mode flycheck-mode + "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) (reverse flycheck-hooks-alist)) + (add-hook hook fn nil 'local)) + + (setq flycheck-old-next-error-function + (if flycheck-standard-error-navigation + next-error-function + :unset)) + (when flycheck-standard-error-navigation + (setq next-error-function #'flycheck-next-error-function)) + + ;; This hook must be added globally since otherwise we cannot + ;; detect a change from a buffer where Flycheck is enabled to a + ;; buffer where Flycheck is not enabled, and therefore cannot + ;; notice that there has been any change when the user switches + ;; back to the buffer where Flycheck is enabled. + (add-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch)) + (t + (unless (eq flycheck-old-next-error-function :unset) + (setq next-error-function flycheck-old-next-error-function)) + + (pcase-dolist (`(,hook . ,fn) flycheck-hooks-alist) + (remove-hook hook fn 'local)) + + (flycheck-teardown)))) + + +;;; Syntax checker selection for the current buffer +(defun flycheck-get-checker-for-buffer () + "Find the checker for the current buffer. + +Use the selected checker for the current buffer, if any, +otherwise search for the best checker from `flycheck-checkers'. + +Return checker if there is a checker for the current buffer, or +nil otherwise." + (if flycheck-checker + (when (flycheck-may-use-checker flycheck-checker) + flycheck-checker) + (seq-find #'flycheck-may-use-checker flycheck-checkers))) + +(defun flycheck-get-next-checker-for-buffer (checker) + "Get the checker to run after CHECKER for the current buffer." + (let ((next (seq-find #'flycheck-may-use-next-checker + (flycheck-checker-get checker 'next-checkers)))) + (when next + (if (symbolp next) next (cdr next))))) + +(defun flycheck-select-checker (checker) + "Select CHECKER for the current buffer. + +CHECKER is a syntax checker symbol (see `flycheck-checkers') or +nil. In the former case, use CHECKER for the current buffer, +otherwise deselect the current syntax checker (if any) and use +automatic checker selection via `flycheck-checkers'. + +If called interactively prompt for CHECKER. With prefix arg +deselect the current syntax checker and enable automatic +selection again. + +Set `flycheck-checker' to CHECKER and automatically start a new +syntax check if the syntax checker changed. + +CHECKER will be used, even if it is not contained in +`flycheck-checkers', or if it is disabled via +`flycheck-disabled-checkers'." + (interactive + (if current-prefix-arg + (list nil) + (list (flycheck-read-checker "Select checker: " + (flycheck-get-checker-for-buffer))))) + (when (not (eq checker flycheck-checker)) + (unless (or (not checker) (flycheck-may-use-checker checker)) + (flycheck-verify-checker checker) + (user-error "Can't use syntax checker %S in this buffer" checker)) + (setq flycheck-checker checker) + (when flycheck-mode + (flycheck-buffer)))) + +(defun flycheck-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--file-truename-cache) + (kill-local-variable 'flycheck--idle-trigger-timer) + (kill-local-variable 'flycheck--idle-trigger-conditions) + (kill-local-variable 'flycheck--last-error-display-tick)) + +(defun flycheck-teardown (&optional ignore-global) + "Teardown Flycheck in the current buffer. + +Completely clear the whole Flycheck state. Remove overlays, kill +running checks, and empty all variables used by Flycheck. + +Unless optional argument IGNORE-GLOBAL is non-nil, check to see +if no more Flycheck buffers remain (aside from the current +buffer), and if so then clean up global hooks." + (flycheck-safe-delete-temporaries) + (flycheck-stop) + (flycheck-clean-deferred-check) + (flycheck-clear) + (flycheck-cancel-error-display-error-at-point-timer) + (flycheck--clear-idle-trigger-timer) + (flycheck--empty-variables) + (unless (or ignore-global + (seq-some (lambda (buf) + (and (not (equal buf (current-buffer))) + (buffer-local-value 'flycheck-mode buf))) + (buffer-list))) + (flycheck-global-teardown 'ignore-local))) + + +;;; Automatic syntax checking in a buffer +(defun flycheck-may-check-automatically (&rest conditions) + "Determine whether the buffer may be checked under one of CONDITIONS. + +Read-only buffers may never be checked automatically. + +If CONDITIONS are given, determine whether syntax may be checked +under at least one of them, according to +`flycheck-check-syntax-automatically'." + (and (not (or buffer-read-only (flycheck-ephemeral-buffer-p))) + (file-exists-p default-directory) + (or (not conditions) + (seq-some + (lambda (condition) + (memq condition flycheck-check-syntax-automatically)) + conditions)))) + +(defvar-local flycheck--idle-trigger-timer nil + "Timer used to trigger a syntax check after an idle delay.") + +(defvar-local flycheck--idle-trigger-conditions nil + "List of conditions under which an idle syntax check will be triggered. +This will be some subset of the allowable values for +`flycheck-check-syntax-automatically'. + +For example, if the user switches to a buffer and then makes an +edit, this list will have the values `idle-change' and +`idle-buffer-switch' in it, at least until the idle timer +expires.") + +(defun flycheck-buffer-automatically (&optional condition force-deferred) + "Automatically check syntax at CONDITION. + +Syntax is not checked if `flycheck-may-check-automatically' +returns nil for CONDITION. (CONDITION may be a single condition +or a list of them.) + +The syntax check is deferred if FORCE-DEFERRED is non-nil, or if +`flycheck-must-defer-check' returns t." + (when (and flycheck-mode (if (listp condition) + (apply #'flycheck-may-check-automatically + condition) + (flycheck-may-check-automatically condition))) + (flycheck--clear-idle-trigger-timer) + (setq flycheck--idle-trigger-conditions nil) + (if (or force-deferred (flycheck-must-defer-check)) + (flycheck-buffer-deferred) + (with-demoted-errors "Error while checking syntax automatically: %S" + (flycheck-buffer))))) + +(defun flycheck--clear-idle-trigger-timer () + "Clear the idle trigger timer." + (when flycheck--idle-trigger-timer + (cancel-timer flycheck--idle-trigger-timer) + (setq flycheck--idle-trigger-timer nil))) + +(defun flycheck--handle-idle-trigger (buffer) + "Run a syntax check in BUFFER if appropriate. +This function is called by `flycheck--idle-trigger-timer'." + (let ((current-buffer (current-buffer))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (unless (or flycheck-buffer-switch-check-intermediate-buffers + (eq buffer current-buffer)) + (setq flycheck--idle-trigger-conditions + (delq 'idle-buffer-switch + flycheck--idle-trigger-conditions))) + (when flycheck--idle-trigger-conditions + (flycheck-buffer-automatically flycheck--idle-trigger-conditions) + (setq flycheck--idle-trigger-conditions nil)))))) + +(defun flycheck-handle-change (beg end _len) + "Handle a buffer change between BEG and END. + +BEG and END mark the beginning and end of the change text. _LEN +is ignored. + +Start a syntax check if a new line has been inserted into the +buffer." + ;; Save and restore the match data, as recommended in (elisp)Change Hooks + (save-match-data + (when flycheck-mode + (if (string-match-p (rx "\n") (buffer-substring beg end)) + (flycheck-buffer-automatically 'new-line 'force-deferred) + (when (memq 'idle-change flycheck-check-syntax-automatically) + (flycheck--clear-idle-trigger-timer) + (cl-pushnew 'idle-change flycheck--idle-trigger-conditions) + (setq flycheck--idle-trigger-timer + (run-at-time flycheck-idle-change-delay nil + #'flycheck--handle-idle-trigger + (current-buffer)))))))) + +(defvar flycheck--last-buffer (current-buffer) + "The current buffer or the buffer that was previously current. +This is usually equal to the current buffer, unless the user just +switched buffers. After a buffer switch, it is the previous +buffer.") + +(defun flycheck-handle-buffer-switch () + "Handle a possible switch to another buffer. + +If a buffer switch actually happened, schedule a syntax check." + ;; Switching buffers here is weird, but unfortunately necessary. It + ;; turns out that `with-temp-buffer' triggers + ;; `buffer-list-update-hook' twice, and the value of + ;; `current-buffer' is bogus in one of those triggers (the one just + ;; after the temp buffer is killed). If we rely on the bogus value, + ;; Flycheck will think that the user is switching back and forth + ;; between different buffers during the `with-temp-buffer' call + ;; (note: two different normal buffers, not the current buffer and + ;; the temp buffer!), and that would trigger spurious syntax checks. + ;; It seems that reading (window-buffer) gets us the correct current + ;; buffer in all important real-life situations (although it doesn't + ;; necessarily catch uses of `set-buffer'). + (with-current-buffer (window-buffer) + (unless (or (equal flycheck--last-buffer (current-buffer)) + ;; Don't bother keeping track of changes to and from + ;; the minibuffer, as they will never require us to + ;; run a syntax check. + (minibufferp)) + (setq flycheck--last-buffer (current-buffer)) + (when (and flycheck-mode + (memq 'idle-buffer-switch flycheck-check-syntax-automatically)) + (flycheck--clear-idle-trigger-timer) + (cl-pushnew 'idle-buffer-switch flycheck--idle-trigger-conditions) + (setq flycheck--idle-trigger-timer + (run-at-time flycheck-idle-buffer-switch-delay nil + #'flycheck--handle-idle-trigger + (current-buffer))))))) + +(defun flycheck-handle-save () + "Handle a save of the buffer." + (flycheck-buffer-automatically 'save)) + + +;;; Deferred syntax checking +(defvar-local flycheck-deferred-syntax-check nil + "If non-nil, a deferred syntax check is pending.") + +(defun flycheck-must-defer-check () + "Determine whether the syntax check has to be deferred. + +A check has to be deferred if the buffer is not visible, or if the buffer is +currently being reverted. + +Return t if the check is to be deferred, or nil otherwise." + (or (not (get-buffer-window)) + ;; We defer the syntax check if Flycheck is already running, to + ;; immediately start a new syntax check after the current one finished, + ;; because the result of the current check will most likely be outdated by + ;; the time it is finished. + (flycheck-running-p) + ;; We must defer checks while a buffer is being reverted, to avoid race + ;; conditions while the buffer contents are being restored. + revert-buffer-in-progress-p)) + +(defun flycheck-deferred-check-p () + "Determine whether the current buffer has a deferred check. + +Return t if so, or nil otherwise." + flycheck-deferred-syntax-check) + +(defun flycheck-buffer-deferred () + "Defer syntax check for the current buffer." + (setq flycheck-deferred-syntax-check t)) + +(defun flycheck-clean-deferred-check () + "Clean a deferred syntax checking state." + (setq flycheck-deferred-syntax-check nil)) + +(defun flycheck-perform-deferred-syntax-check () + "Perform the deferred syntax check." + (when (flycheck-deferred-check-p) + (flycheck-clean-deferred-check) + (flycheck-buffer-automatically))) + + +;;; Syntax checking in all buffers +(defun flycheck-may-enable-mode () + "Determine whether Flycheck mode may be enabled. + +Flycheck mode is not enabled for + +- the minibuffer, +- `fundamental-mode' +- major modes whose `mode-class' property is `special', +- ephemeral buffers (see `flycheck-ephemeral-buffer-p'), +- encrypted buffers (see `flycheck-encrypted-buffer-p'), +- remote files (see `file-remote-p'), +- and major modes excluded by `flycheck-global-modes'. + +Return non-nil if Flycheck mode may be enabled, and nil +otherwise." + (and (pcase flycheck-global-modes + ;; Whether `major-mode' is disallowed by `flycheck-global-modes' + (`t t) + (`(not . ,modes) (not (memq major-mode modes))) + (modes (memq major-mode modes))) + (not (or (minibufferp) + (eq major-mode 'fundamental-mode) + (eq (get major-mode 'mode-class) 'special) + (flycheck-ephemeral-buffer-p) + (flycheck-encrypted-buffer-p) + (and (buffer-file-name) + (file-remote-p (buffer-file-name) 'method)))))) + +(defun flycheck-mode-on-safe () + "Enable command `flycheck-mode' if it is safe to do so. + +Command `flycheck-mode' is only enabled if +`flycheck-may-enable-mode' returns a non-nil result." + (when (flycheck-may-enable-mode) + (flycheck-mode))) + +;;;###autoload +(define-globalized-minor-mode global-flycheck-mode flycheck-mode + flycheck-mode-on-safe + :init-value nil + ;; Do not expose Global Flycheck Mode on customize interface, because the + ;; interaction between package.el and customize is currently broken. See + ;; https://github.com/flycheck/flycheck/issues/595 + + ;; :require 'flycheck :group + ;; 'flycheck + ) + +(defun flycheck-global-teardown (&optional ignore-local) + "Teardown Flycheck in all buffers. + +Completely clear the whole Flycheck state in all buffers, stop +all running checks, remove all temporary files, and empty all +variables of Flycheck. + +Also remove global hooks. (If optional argument IGNORE-LOCAL is +non-nil, then only do this and skip per-buffer teardown.)" + (unless ignore-local + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (when flycheck-mode + (flycheck-teardown 'ignore-global))))) + (remove-hook 'buffer-list-update-hook #'flycheck-handle-buffer-switch)) + +;; Clean up the entire state of Flycheck when Emacs is killed, to get rid of any +;; pending temporary files. +(add-hook 'kill-emacs-hook #'flycheck-global-teardown) + + +;;; Errors from syntax checks +(cl-defstruct (flycheck-error + (:constructor nil) + (:constructor + flycheck-error-new + (&key + line column end-line end-column + buffer checker filename message level id group + &aux (-end-line end-line) (-end-column end-column))) + (:constructor + flycheck-error-new-at + (line + column + &optional level message + &key end-line end-column checker id group + (filename (buffer-file-name)) (buffer (current-buffer)) + &aux (-end-line end-line) (-end-column end-column))) + (:constructor + flycheck-error-new-at-pos + (pos + &optional level message + &key end-pos checker id group + (filename (buffer-file-name)) (buffer (current-buffer)) + &aux + ((line . column) + (if pos (flycheck-line-column-at-pos pos) + '(nil . nil))) + ((-end-line . -end-column) + (if end-pos (flycheck-line-column-at-pos end-pos) + '(nil . nil)))))) + "Structure representing an error reported by a syntax checker. +Slots: + +`buffer' + The buffer that the error was reported for, as buffer object. + +`checker' + The syntax checker which reported this error, as symbol. + +`filename' + The file name the error refers to, as string. + +`line' + The line on which the error starts, as number. + +`column' (optional) + The column at which the error starts, as number. + + For compatibility with external tools and unlike Emacs + itself (e.g. in Compile Mode) Flycheck uses _1-based_ + columns: The first character on a line is column 1. + + Occasionally some tools try to proactively adapt to Emacs + and emit 0-based columns automatically. In these cases, the + columns must be adjusted for Flycheck, see + `flycheck-increment-error-columns'. + + If nil, the whole line is highlighted. + +`end-line' (optional) + The line on which the error ends. If nil, this is computed according to + `flycheck-highlighting-mode'. + +`end-column' + The column at which the error ends. If nil, this is computed according to + `flycheck-highlighting-mode'. Error intervals are right-open: the + end-column points to the first character not included in the error. For + example, 1:1 is an empty range. and in \"line-number-at-pos\", the range + 6:12 covers the word \"number\". + +`message' (optional) + The error message as a string, if any. + +`level' + The error level, as either `info', `warning' or `error'. + +`id' (optional) + An ID identifying the kind of error. + +`group' (optional) + A symbol identifying the group the error belongs to. + + Some tools will emit multiple errors that relate to the same + issue (e.g., lifetime errors in Rust). All related errors + collected by a checker should have the same `group` value, + in order to be able to present them to the user. + + See `flycheck-related-errors`." + buffer checker filename line column message level id group + ;; The fields below are at the end of the record to preserve backwards + ;; compatibility; see https://github.com/flycheck/flycheck/pull/1400 and + ;; https://lists.gnu.org/archive/html/emacs-devel/2018-07/msg00436.html + -end-line -end-column) + +;; These accessors are defined for backwards compatibility +;; FIXME: Clean up once package.el learns how to recompile dependencies. + +(defun flycheck-error-end-line (err) + "Return the end line of a Flycheck error ERR." + (condition-case nil (flycheck-error--end-line err) + (args-out-of-range nil))) + +(defun flycheck-error-end-column (err) + "Return the end column of a Flycheck error ERR." + (condition-case nil (flycheck-error--end-column err) + (args-out-of-range nil))) + +(defun flycheck-error--set-end-line (err line) + "Set the end line of a Flycheck error ERR to LINE." + (condition-case nil (setf (flycheck-error--end-line err) line) + (args-out-of-range nil))) + +(defun flycheck-error--set-end-column (err column) + "Set the end column of a Flycheck error ERR to COLUMN." + (condition-case nil (setf (flycheck-error--end-column err) column) + (args-out-of-range nil))) + +(gv-define-simple-setter flycheck-error-end-line + flycheck-error--set-end-line) +(gv-define-simple-setter flycheck-error-end-column + flycheck-error--set-end-column) + +(defmacro flycheck-error-with-buffer (err &rest forms) + "Switch to the buffer of ERR and evaluate FORMS. + +If the buffer of ERR is not live, FORMS are not evaluated." + (declare (indent 1) (debug t)) + `(when (buffer-live-p (flycheck-error-buffer ,err)) + (with-current-buffer (flycheck-error-buffer ,err) + ,@forms))) + +(defun flycheck--exact-region (line col end-line end-col) + "Get the region of range LINE, COL, END-LINE, END-COL. + +Return a cons cell `(BEG . END)'. If the input range is empty, +it is expanded to cover at least one character so that END is +always greater than BEG." + (let ((beg (flycheck-line-column-to-position line col)) + (end (flycheck-line-column-to-position end-line end-col))) + (cond + ((< beg end) (cons beg end)) + ((= end (point-max)) (cons (1- end) end)) + (t (cons end (1+ end)))))) + +(defun flycheck--line-region (pos) + "Get the line region of position POS. + +Return a cons cell `(BEG . END)' where BEG is the first +non-whitespace character on the line ERR refers to, and END the +end of the line." + (save-excursion + (goto-char pos) + (forward-line 0) + (let ((bol (point)) + (end (line-end-position))) + ;; Move to the beginning of this line's indentation, similar to + ;; `back-to-indentation' + (skip-syntax-forward " " end) + (backward-prefix-chars) + ;; If the current line is blank, highlight it in full; if it's + ;; empty, include the previous line break character(s) to have + ;; any region at all (when called with 0, `line-end-position' + ;; gives us the end of the previous line). + (cons (if (eolp) (if (= bol end) (line-end-position 0) bol) (point)) + end)))) + +(defun flycheck--column-region (pos) + "Get the column region of position POS. + +Return a cons cell `(BEG . END)' where BEG is the character +before the column, and END the actual column." + (save-excursion + (goto-char pos) + ;; (eobp): No enough lines in the buffer + (if (eobp) (cons (1- (point-max)) (point-max)) + (cons pos (1+ pos))))) + +(defun flycheck-bounds-of-thing-at-point (thing pos) + "Get the region of THING at position POS. + +THING is a understood by `thing-at-point'. + +Return a cons cell `(BEG . END)' where BEG is the beginning of +the THING at the column, and END the end of the THING." + (save-excursion + (goto-char pos) + (bounds-of-thing-at-point thing))) + +(defun flycheck--approximate-region (line column mode) + "Compute the region of LINE, COLUMN based on MODE." + (let* ((beg (flycheck-line-column-to-position line (or column 1)))) + (if (or (null column) + (eq mode 'lines)) + (flycheck--line-region beg) + (or (pcase mode + (`symbols + ;; Ensure that we're on a word or symbol. See + ;; https://github.com/flycheck/flycheck/issues/1519 + (and (< beg (point-max)) + (memq (char-syntax (char-after beg)) '(?w ?_)) + (flycheck-bounds-of-thing-at-point 'symbol beg))) + (`sexps + (flycheck-bounds-of-thing-at-point 'sexp beg))) + (flycheck--column-region beg))))) + +(defun flycheck-error-region-for-mode (err mode) + "Get the region of ERR for the highlighting MODE. + +ERR is a Flycheck error. If its position is fully specified, use +that to compute a region; otherwise, use MODE, as documented in +`flycheck-highlighting-mode'. If MODE is nil, signal an error." + (flycheck-error-with-buffer err + (save-excursion + (save-restriction + (widen) + ;; Ignoring fields speeds up calls to `line-end-position'. + (let* ((inhibit-field-text-motion t) + (line (flycheck-error-line err)) + (column (flycheck-error-column err)) + (end-line (or (flycheck-error-end-line err) line)) + (end-column (flycheck-error-end-column err))) + (if (and line column end-line end-column) + (flycheck--exact-region line column end-line end-column) + (flycheck--approximate-region line column mode))))))) + +(defun flycheck-error-pos (err) + "Get the buffer position of ERR. + +ERR is a Flycheck error whose position to get. + +The error position is the error column, or the first +non-whitespace character of the error line, if ERR has no error column." + (car (flycheck-error-region-for-mode err 'columns))) + +(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-position (err) + "Format the position of ERR as a human-readable string." + (let ((line (flycheck-error-line err)) + (column (flycheck-error-column err)) + (end-line (flycheck-error-end-line err)) + (end-column (flycheck-error-end-column err))) + (if (and line column) + (if (or (null end-line) (equal line end-line)) + (if (or (null end-column) (equal column (1- end-column))) + (format "%d:%d" line column) + (format "%d:%d-%d" line column end-column)) + (format "(%d:%d)-(%d:%d)" line column end-line end-column)) + (if (or (null end-line) (equal line end-line)) + (format "%d" line) + (format "%d-%d" line end-line))))) + +(defun flycheck-error-format (err &optional with-file-name) + "Format ERR as human-readable string, optionally WITH-FILE-NAME. + +Return a string that represents the given ERR. If WITH-FILE-NAME +is given and non-nil, include the file-name as well, otherwise +omit it." + (let* ((level (symbol-name (flycheck-error-level err))) + (checker (symbol-name (flycheck-error-checker err))) + (format `(,@(when with-file-name + (list (flycheck-error-filename err) ":")) + ,(flycheck-error-format-position err) ":" + ,level ": " + ,(flycheck-error-format-message-and-id err) + " (" ,checker ")"))) + (apply #'concat format))) + +(defun flycheck-error-< (err1 err2) + "Determine whether ERR1 is less than ERR2 by location." + (let ((l1 (flycheck-error-line err1)) + (l2 (flycheck-error-line err2))) + (if (/= l1 l2) + (< l1 l2) + (let ((c1 (or (flycheck-error-column err1) 1)) + (c2 (or (flycheck-error-column err2) 1))) + (if (/= c1 c2) + (< c1 c2) + (let ((el1 (or (flycheck-error-end-line err1) l1)) + (el2 (or (flycheck-error-end-line err2) l2))) + (if (/= el1 el2) + (< el1 el2) + (let ((cl1 (or (flycheck-error-end-column err1) 1)) + (cl2 (or (flycheck-error-end-column err2) 1))) + (< cl1 cl2))))))))) + +(defun flycheck-error-level-< (err1 err2) + "Determine whether ERR1 is less than ERR2 by error level. + +Like `flycheck-error-<', but compares by error level severity +first. Levels of the same severity are compared by name." + (let* ((level1 (flycheck-error-level err1)) + (level2 (flycheck-error-level err2)) + (severity1 (flycheck-error-level-severity level1)) + (severity2 (flycheck-error-level-severity level2))) + (cond + ((= severity1 severity2) + (if (string= level1 level2) + (flycheck-error-< err1 err2) + (string< level1 level2))) + (t (< severity1 severity2))))) + +(defun flycheck-assert-error-list-p (errors) + "Assert that all items in ERRORS are of `flycheck-error' type. + +Signal an error if any item in ERRORS is not a `flycheck-error' +object, as by `flycheck-error-p'. Otherwise return ERRORS +again." + (unless (listp errors) + (signal 'wrong-type-argument (list 'listp errors))) + (dolist (err errors) + (unless (flycheck-error-p err) + (signal 'wrong-type-argument (list 'flycheck-error-p err)))) + errors) + + +;;; Errors in the current buffer +(defvar-local flycheck-current-errors nil + "A list of all errors and warnings in the current buffer.") + +(defun flycheck-report-current-errors (errors) + "Report ERRORS in the current buffer. + +Add ERRORS to `flycheck-current-errors' and process each error +with `flycheck-process-error-functions'." + (setq flycheck-current-errors (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)) + ;; Errors without line numbers are discarded. If a linter + ;; reports relevant errors without line numbers, use + ;; `flycheck-fill-empty-line-numbers' as the checker's + ;; `:error-filter' to set them to line 0. + (flycheck-error-line err))))) + +(defun flycheck-relevant-errors (errors) + "Filter the relevant errors from ERRORS. + +Return a list of all errors that are relevant for their +corresponding buffer." + (seq-filter #'flycheck-relevant-error-p errors)) + +(defun flycheck-related-errors (err &optional error-set) + "Get all the errors that are in the same group as ERR. + +Return a list of all errors (from ERROR-SET) that have the same +`flycheck-error-group' as ERR, including ERR itself. + +If ERROR-SET is nil, `flycheck-current-errors' is used instead." + (let ((group (flycheck-error-group err)) + (checker (flycheck-error-checker err))) + (if group + (seq-filter (lambda (e) + (and (eq (flycheck-error-checker e) checker) + (eq (flycheck-error-group e) group))) + (or error-set flycheck-current-errors)) + (list err)))) + + +;;; Status reporting for the current buffer +(defvar-local flycheck-last-status-change 'not-checked + "The last status change in the current buffer.") + +(defun flycheck-report-failed-syntax-check (&optional status) + "Report a failed Flycheck syntax check with STATUS. + +STATUS is a status symbol for `flycheck-report-status', +defaulting to `errored'. + +Clear Flycheck state, run `flycheck-syntax-check-failed-hook' and +report an error STATUS." + (flycheck-clear) + (setq flycheck-current-syntax-check nil) + (run-hooks 'flycheck-syntax-check-failed-hook) + (flycheck-report-status (or status 'errored))) + +(defun flycheck-report-status (status) + "Report Flycheck STATUS. + +STATUS is one of the following symbols: + +`not-checked' + The current buffer was not checked. + +`no-checker' + Automatic syntax checker selection did not find a suitable + syntax checker. + +`running' + A syntax check is now running in the current buffer. + +`errored' + The current syntax check has errored. + +`finished' + The current syntax check was finished normally. + +`interrupted' + The current syntax check was interrupted. + +`suspicious' + The last syntax check had a suspicious result. + +Set `flycheck-last-status-change' and call +`flycheck-status-changed-functions' with STATUS. Afterwards +refresh the mode line." + (setq flycheck-last-status-change status) + (run-hook-with-args 'flycheck-status-changed-functions status) + (force-mode-line-update)) + +(defun flycheck-mode-line-status-text (&optional status) + "Get a text describing STATUS for use in the mode line. + +STATUS defaults to `flycheck-last-status-change' if omitted or +nil." + (let ((text (pcase (or status flycheck-last-status-change) + (`not-checked "") + (`no-checker "-") + (`running "*") + (`errored "!") + (`finished + (let-alist (flycheck-count-errors flycheck-current-errors) + (if (or .error .warning) + (format ":%s/%s" (or .error 0) (or .warning 0)) + ""))) + (`interrupted ".") + (`suspicious "?")))) + (concat " " flycheck-mode-line-prefix text))) + + +;;; Error levels +;;;###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)) + (id (flycheck-error-id err))) + (when message + (setq message (string-trim message)) + (setf (flycheck-error-message err) + (if (string-empty-p message) nil message))) + (when (and id (string-empty-p id)) + (setf (flycheck-error-id err) nil)) + (when (eq (flycheck-error-column err) 0) + (setf (flycheck-error-column err) nil)) + (when (eq (flycheck-error-end-column err) 0) + (setf (flycheck-error-end-column err) nil))))) + errors) + +(defun flycheck-remove-error-file-names (file-name errors) + "Remove matching FILE-NAME from ERRORS. + +Use as `:error-filter' for syntax checkers that output faulty +filenames. Flycheck will later fill in the buffer file name. + +Return ERRORS." + (seq-do (lambda (err) + (when (and (flycheck-error-filename err) + (string= (flycheck-error-filename err) file-name)) + (setf (flycheck-error-filename err) nil))) + errors) + errors) + +(defun flycheck-increment-error-columns (errors &optional offset) + "Increment all columns of ERRORS by OFFSET (default: 1). + + Use this as `:error-filter' if a syntax checker outputs 0-based + columns." + (setq offset (or offset 1)) ;; Emacs bug #31715 + (seq-do (lambda (err) + (when (flycheck-error-column err) + (cl-incf (flycheck-error-column err) offset)) + (when (flycheck-error-end-column err) + (cl-incf (flycheck-error-end-column err) offset))) + errors) + errors) + +(defun flycheck-collapse-error-message-whitespace (errors) + "Collapse whitespace in all messages of ERRORS. + +Return ERRORS." + (dolist (err errors) + (-when-let (message (flycheck-error-message err)) + (setf (flycheck-error-message err) + (replace-regexp-in-string (rx (one-or-more (any space "\n" "\r"))) + " " message 'fixed-case 'literal)))) + errors) + +(defun flycheck-dedent-error-messages (errors) + "Dedent all messages of ERRORS. + +For each error in ERRORS, determine the indentation offset from +the leading whitespace of the first line, and dedent all further +lines accordingly. + +Return ERRORS, with in-place modifications." + (dolist (err errors) + (-when-let (message (flycheck-error-message err)) + (with-temp-buffer + (insert message) + ;; Determine the indentation offset + (goto-char (point-min)) + (back-to-indentation) + (let* ((indent-offset (- (point) (point-min)))) + ;; Now iterate over all lines and dedent each according to + ;; `indent-offset' + (while (not (eobp)) + (back-to-indentation) + ;; If the current line starts with sufficient whitespace, delete the + ;; indentation offset. Otherwise keep the line intact, as we might + ;; loose valuable information + (when (>= (- (point) (line-beginning-position)) indent-offset) + (delete-char (- indent-offset))) + (forward-line 1))) + (delete-trailing-whitespace (point-min) (point-max)) + (setf (flycheck-error-message err) + (buffer-substring-no-properties (point-min) (point-max)))))) + errors) + +(defun flycheck-fold-include-levels (errors sentinel-message) + "Fold levels of ERRORS from included files. + +ERRORS is a list of `flycheck-error' objects. SENTINEL-MESSAGE +is a regular expression matched against the error message to +determine whether the error denotes errors from an included +file. Alternatively, it is a function that is given an error and +shall return non-nil, if the error denotes errors from an +included file." + (unless (or (stringp sentinel-message) (functionp sentinel-message)) + (error "Sentinel must be string or function: %S" sentinel-message)) + (let ((sentinel (if (functionp sentinel-message) + sentinel-message + (lambda (err) + (string-match-p sentinel-message + (flycheck-error-message err))))) + (remaining-errors errors)) + (while remaining-errors + (let* ((current-error (pop remaining-errors))) + (when (funcall sentinel current-error) + ;; We found an error denoting errors in the included file: + ;; 1. process all subsequent errors until faulty include file is found + ;; 2. process again all subsequent errors until an error has the + ;; current file name again + ;; 3. find the most severe error level + (let ((current-filename (flycheck-error-filename current-error)) + (current-level nil) + (faulty-include-filename nil) + (filename nil) + (done (null remaining-errors))) + + (while (not done) + (setq filename (flycheck-error-filename (car remaining-errors))) + (unless faulty-include-filename + (unless (string= filename current-filename) + (setq faulty-include-filename filename))) + + (let* ((error-in-include (pop remaining-errors)) + (in-include-level (flycheck-error-level error-in-include))) + (unless (funcall sentinel error-in-include) + ;; Ignore nested "included file" errors, we are only + ;; interested in real errors because these define our level + (when (or (not current-level) + (> (flycheck-error-level-severity in-include-level) + (flycheck-error-level-severity current-level))) + (setq current-level in-include-level)))) + + (setq done (or (null remaining-errors) + (and faulty-include-filename + (string= filename current-filename))))) + + (setf (flycheck-error-level current-error) current-level + (flycheck-error-message current-error) + (format "In include %s" faulty-include-filename)))))) + errors)) + +(defun flycheck-dequalify-error-ids (errors) + "De-qualify error ids in ERRORS. + +Remove all qualifications from error ids in ERRORS, by stripping +all leading dotted components from error IDs. For instance, if +the error ID is com.foo.E100, replace it with E100. + +This error filter is mainly useful to simplify error IDs obtained +from parsing Checkstyle XML, which frequently has very verbose +IDs, that include the name of the tool." + (seq-do (lambda (err) + (let ((id (flycheck-error-id err))) + (when id + (setf (flycheck-error-id err) + (replace-regexp-in-string + (rx string-start + (group + (optional (zero-or-more not-newline) ".")) + (one-or-more (not (any "."))) + string-end) + "" id 'fixedcase 'literal 1))))) + errors) + errors) + +(defun flycheck-remove-error-ids (errors) + "Remove all error ids from ERRORS." + (seq-do (lambda (err) (setf (flycheck-error-id err) nil)) errors) + errors) + +(defun flycheck-fill-empty-line-numbers (errors) + "Set ERRORS without lines to line 0. + +Use as `:error-filter' for syntax checkers that output errors +without line numbers. + +Return ERRORS." + (seq-do (lambda (err) + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 0))) + errors) + errors) + + +;;; Error analysis +(defun flycheck-count-errors (errors) + "Count the number of ERRORS, grouped by level. + +Return an alist, where each ITEM is a cons cell whose `car' is an +error level, and whose `cdr' is the number of errors of that +level." + (let (counts-by-level) + (dolist (err errors) + (let* ((level (flycheck-error-level err)) + (item (assq level counts-by-level))) + (if item + (cl-incf (cdr item)) + (push (cons level 1) counts-by-level)))) + counts-by-level)) + +(defun flycheck-has-max-errors-p (errors level) + "Check if there is no error in ERRORS more severe than LEVEL." + (let ((severity (flycheck-error-level-severity level))) + (seq-every-p (lambda (e) (<= (flycheck-error-level-severity + (flycheck-error-level e)) + severity)) + errors))) + +(defun flycheck-has-max-current-errors-p (level) + "Check if there is no current error more severe than LEVEL." + (flycheck-has-max-errors-p flycheck-current-errors level)) + +(defun flycheck-has-errors-p (errors level) + "Determine if there are any ERRORS with LEVEL." + (seq-some (lambda (e) (eq (flycheck-error-level e) level)) errors)) + +(defun flycheck-has-current-errors-p (&optional level) + "Determine if the current buffer has errors with LEVEL. + +If LEVEL is omitted if the current buffer has any errors at all." + (if level + (flycheck-has-errors-p flycheck-current-errors level) + (and flycheck-current-errors t))) + + +;;; Error overlays in the current buffer +(defvar-local flycheck--last-overlay-index 0 + "Last index given to a Flycheck overlay. + +These indices are used to preserve error order (Emacs doesn't +preserve overlay order when calling `overlays-at').") + +(defun flycheck--next-overlay-index () + "Compute the index to assign to a new Flycheck overlay." + (cl-incf flycheck--last-overlay-index)) + +(defun flycheck-add-overlay (err) + "Add overlay for ERR. + +Return the created overlay." + ;; We must have a proper error region for the sake of fringe indication, + ;; error display and error navigation, even if the highlighting is disabled. + ;; We erase the highlighting later on in this case + (pcase-let* ((`(,beg . ,end) + (if (flycheck-relevant-error-other-file-p err) + ;; Display overlays for other-file errors on the first line + (cons (point-min) + (save-excursion (goto-char (point-min)) + (point-at-eol))) + (flycheck-error-region-for-mode + err (or flycheck-highlighting-mode 'lines)))) + (overlay (make-overlay beg end)) + (level (flycheck-error-level err)) + (category (flycheck-error-level-overlay-category level)) + (index (flycheck--next-overlay-index))) + (unless (flycheck-error-level-p level) + (error "Undefined error level: %S" level)) + (setf (overlay-get overlay 'flycheck-error-index) index) + (setf (overlay-get overlay 'flycheck-overlay) t) + (setf (overlay-get overlay 'flycheck-error) err) + (setf (overlay-get overlay 'category) category) + (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))))) + errs "\n\n")) + +(defun flycheck-filter-overlays (overlays) + "Get all Flycheck overlays from OVERLAYS, in original order." + ;; The order of errors returned from overlays is not stable, so we sort + ;; them again using the internal index to guarantee errors are always + ;; displayed in the same order. + (seq-sort + (lambda (o1 o2) (< (overlay-get o1 'flycheck-error-index) + (overlay-get o2 'flycheck-error-index))) + (seq-filter (lambda (o) (overlay-get o 'flycheck-overlay)) overlays))) + +(defun flycheck-overlays-at (pos) + "Get all Flycheck overlays at POS." + (flycheck-filter-overlays (overlays-at pos))) + +(defun flycheck-overlays-in (beg end) + "Get all Flycheck overlays between BEG and END." + (flycheck-filter-overlays (overlays-in beg end))) + +(defun flycheck-overlay-errors-at (pos) + "Return a list of all flycheck errors overlaid at POS." + (seq-map (lambda (o) (overlay-get o 'flycheck-error)) + (flycheck-overlays-at pos))) + +(defun flycheck-overlay-errors-in (beg end) + "Return a list of all flycheck errors overlaid between BEG and END." + (seq-map (lambda (o) (overlay-get o 'flycheck-error)) + (flycheck-overlays-in beg end))) + +(defvar-local flycheck-overlays-to-delete nil + "Overlays mark for deletion after all syntax checks completed.") +(put 'flycheck-overlays-to-delete 'permanent-local t) + +(defun flycheck-delete-all-overlays () + "Remove all flycheck overlays in the current buffer." + (overlay-recenter (point-max)) + (flycheck-delete-marked-overlays) + (setq flycheck--last-overlay-index 0) + (save-restriction + (widen) + (seq-do #'delete-overlay (flycheck-overlays-in (point-min) (point-max))))) + +(defun flycheck-mark-all-overlays-for-deletion () + "Mark all current overlays for deletion." + (setq flycheck-overlays-to-delete + (append (flycheck-overlays-in (point-min) (point-max)) + flycheck-overlays-to-delete))) + +(defun flycheck-delete-marked-overlays () + "Delete all overlays marked for deletion." + (overlay-recenter (point-max)) + (seq-do #'delete-overlay flycheck-overlays-to-delete) + (setq flycheck-overlays-to-delete nil)) + + +;;; Error navigation in the current buffer +(defun flycheck-error-level-interesting-at-pos-p (pos) + "Check if error severity at POS passes `flycheck-error-level-interesting-p'." + (flycheck-error-level-interesting-p (get-char-property pos 'flycheck-error))) + +(defun flycheck-error-level-interesting-p (err) + "Check if ERR severity is >= `flycheck-navigation-minimum-level'. + +ERR is also interesting (the function returns true) if there are +no errors as or more severe than `flycheck-navigation-minimum-level'." + (when (flycheck-error-p err) + (-if-let (min-level flycheck-navigation-minimum-level) + (or (<= (flycheck-error-level-severity min-level) + (flycheck-error-level-severity (flycheck-error-level err))) + (not (flycheck-has-current-errors-p min-level))) + t))) + +(defun flycheck-next-error-pos (n &optional reset) + "Get the position of the N-th next error. + +With negative N, get the position of the (-N)-th previous error +instead. With non-nil RESET, search from `point-min', otherwise +search from the current point. + +Return the position of the next or previous error, or nil if +there is none. If N is zero, return `point', or `point-min' if +RESET is non-nil." + (let ((n (or n 1)) + (pos (if reset (point-min) (point)))) + (if (>= n 0) + ;; Search forwards + (while (and pos (> n 0)) + (setq n (1- n)) + (when (get-char-property pos 'flycheck-error) + ;; Move beyond from the current error if any + (setq pos (next-single-char-property-change pos 'flycheck-error))) + (while (not (or (= pos (point-max)) + (flycheck-error-level-interesting-at-pos-p pos))) + ;; Scan for the next error + (setq pos (next-single-char-property-change pos 'flycheck-error))) + (when (and (= pos (point-max)) + (not (flycheck-error-level-interesting-at-pos-p pos))) + ;; If we reached the end of the buffer, but no error, we didn't find + ;; any + (setq pos nil))) + ;; Search backwards + (while (and pos (< n 0)) + (setq n (1+ n)) + ;; Loop until we find an error. We need to check the position *before* + ;; the current one, because `previous-single-char-property-change' + ;; always moves to the position *of* the change. + (while (not (or (= pos (point-min)) + (flycheck-error-level-interesting-at-pos-p (1- pos)))) + (setq pos (previous-single-char-property-change pos 'flycheck-error))) + (when (and (= pos (point-min)) + (not (flycheck-error-level-interesting-at-pos-p pos))) + ;; We didn't find any error. + (setq pos nil)) + (when pos + ;; We found an error, so move to its beginning + (setq pos (previous-single-char-property-change pos + 'flycheck-error))))) + pos)) + +(defun flycheck-next-error-function (n reset) + "Visit the N-th error from the current point. + +N is the number of errors to advance by, where a negative N +advances backwards. With non-nil RESET, advance from the +beginning of the buffer, otherwise advance from the current +position. + +Intended for use with `next-error-function'." + (-if-let* ((pos (flycheck-next-error-pos n reset)) + (err (get-char-property pos 'flycheck-error))) + (flycheck-jump-to-error err) + (user-error "No more Flycheck errors"))) + +(defun flycheck-next-error (&optional n reset) + "Visit the N-th error from the current point. + +N is the number of errors to advance by, where a negative N +advances backwards. With non-nil RESET, advance from the +beginning of the buffer, otherwise advance from the current +position." + (interactive "P") + (when (consp n) + ;; Universal prefix argument means reset + (setq reset t n nil)) + (flycheck-next-error-function n reset) + (flycheck-display-error-at-point)) + +(defun flycheck-previous-error (&optional n) + "Visit the N-th previous error. + +If given, N specifies the number of errors to move backwards by. +If N is negative, move forwards instead." + (interactive "P") + (flycheck-next-error (- (or n 1)))) + +(defun flycheck-first-error (&optional n) + "Visit the N-th error from beginning of the buffer. + +If given, N specifies the number of errors to move forward from +the beginning of the buffer." + (interactive "P") + (flycheck-next-error n 'reset)) + + +;;; Listing errors in buffers +(defconst flycheck-error-list-buffer "*Flycheck errors*" + "The name of the buffer to show error lists.") + +(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 + (unless (with-no-warnings + (seq-contains flycheck-current-errors error-copy 'equal)) + (when flycheck-mode + (flycheck-buffer)))))))) + +(defun flycheck-jump-in-buffer (buffer error) + "In BUFFER, jump to ERROR." + ;; FIXME: we assume BUFFER and the buffer of ERROR are the same. We don't + ;; need the first argument then. + (if (eq (window-buffer) (get-buffer flycheck-error-list-buffer)) + ;; When called from within the error list, keep the error list, + ;; otherwise replace the current buffer. + (pop-to-buffer buffer 'other-window) + (switch-to-buffer buffer)) + (let ((pos (flycheck-error-pos error))) + (unless (eq (goto-char pos) (point)) + ;; If widening gets in the way of moving to the right place, remove it + ;; and try again + (widen) + (goto-char pos))) + ;; Re-highlight the errors. We have post-command-hook for that, but calls to + ;; `flycheck-jump-in-buffer' that come from other buffers (e.g. from the error + ;; list) won't trigger it. + (flycheck-error-list-highlight-errors 'preserve-pos)) + +(defun flycheck-error-list-explain-error (&optional pos) + "Explain the error at POS in the error list. + +POS defaults to `point'." + (interactive) + (-when-let* ((error (tabulated-list-get-id pos)) + (explainer (flycheck-checker-get (flycheck-error-checker error) + 'error-explainer)) + (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) + (with-current-buffer flycheck-error-list-buffer + (let ((current-errors + (when (buffer-live-p flycheck-error-list-source-buffer) + (with-current-buffer flycheck-error-list-source-buffer + (flycheck-overlay-errors-in (line-beginning-position) + (line-end-position)))))) + (let ((old-overlays flycheck-error-list-highlight-overlays) + (min-point (point-max)) + (max-point (point-min))) + ;; Display the new overlays first, to avoid re-display flickering + (setq flycheck-error-list-highlight-overlays nil) + (when current-errors + (let ((next-error-pos (point-min))) + (while next-error-pos + (let* ((beg next-error-pos) + (end (flycheck-error-list-next-error-pos beg)) + (err (tabulated-list-get-id beg))) + (when (member err current-errors) + (setq min-point (min min-point beg) + max-point (max max-point beg)) + (let ((ov (make-overlay beg + ;; Extend overlay to the beginning + ;; of the next line, to highlight + ;; the whole line + (or end (point-max))))) + (push ov flycheck-error-list-highlight-overlays) + (setf (overlay-get ov 'flycheck-error-highlight-overlay) + t) + (setf (overlay-get ov 'face) + 'flycheck-error-list-highlight))) + (setq next-error-pos end))))) + ;; Delete the old overlays + (seq-do #'delete-overlay old-overlays) + (when (and (not preserve-pos) current-errors) + ;; Move point to the middle error + (goto-char (+ min-point (/ (- max-point min-point) 2))) + (beginning-of-line) + ;; And recenter the error list at this position + (flycheck-error-list-recenter-at (point)))))))) + +(defun flycheck-list-errors () + "Show the error list for the current buffer." + (interactive) + (unless flycheck-mode + (user-error "Flycheck mode not enabled")) + ;; Create and initialize the error list + (unless (get-buffer flycheck-error-list-buffer) + (with-current-buffer (get-buffer-create flycheck-error-list-buffer) + (flycheck-error-list-mode))) + (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 errors.") + +(defun flycheck-cancel-error-display-error-at-point-timer () + "Cancel the error display timer for the current buffer." + (when flycheck-display-error-at-point-timer + (cancel-timer flycheck-display-error-at-point-timer) + (setq flycheck-display-error-at-point-timer nil))) + +(defun flycheck--error-display-tick () + "Return point and tick counter of current buffer." + (cons (point) (buffer-modified-tick))) + +(defvar-local flycheck--last-error-display-tick nil + "Value of `flycheck--error-display-tick' when errors were last displayed.") + +(defun flycheck-display-error-at-point () + "Display all the error messages at point." + (interactive) + ;; This function runs from a timer, so we must take care to not ignore any + ;; errors + (with-demoted-errors "Flycheck error display error: %s" + (flycheck-cancel-error-display-error-at-point-timer) + (setq flycheck--last-error-display-tick (flycheck--error-display-tick)) + (when flycheck-mode + (-when-let (errors (flycheck-overlay-errors-at (point))) + (flycheck-display-errors errors))))) + +(defun flycheck-display-error-at-point-soon () + "Display error messages at point, with a delay." + (setq flycheck--last-error-display-tick nil) + (flycheck-maybe-display-error-at-point-soon)) + +(defun flycheck-maybe-display-error-at-point-soon () + "Display error message at point with a delay, unless already displayed." + (flycheck-cancel-error-display-error-at-point-timer) + (when (and (not (equal flycheck--last-error-display-tick + (setq flycheck--last-error-display-tick + (flycheck--error-display-tick)))) + (flycheck-overlays-at (point))) + (setq flycheck-display-error-at-point-timer + (run-at-time flycheck-display-errors-delay nil + 'flycheck-display-error-at-point)))) + + +;;; Functions to display errors +(defconst flycheck-error-message-buffer "*Flycheck error messages*" + "The name of the buffer to show long error messages in.") + +(defun flycheck-error-message-buffer () + "Get the buffer object to show long error messages in. + +Get the buffer named by variable `flycheck-error-message-buffer', +or nil if the buffer does not exist." + (get-buffer flycheck-error-message-buffer)) + +(defun flycheck-may-use-echo-area-p () + "Determine whether the echo area may be used. + +The echo area may be used if the cursor is not in the echo area, +and if the echo area is not occupied by minibuffer input." + (not (or cursor-in-echo-area (active-minibuffer-window)))) + +(define-derived-mode flycheck-error-message-mode text-mode + "Flycheck error messages" + "Major mode for extended error messages.") + +(defun flycheck-display-error-messages (errors) + "Display the messages of ERRORS. + +Concatenate all non-nil messages of ERRORS 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))) + (display-message-or-buffer (string-join messages "\n\n") + flycheck-error-message-buffer + 'not-this-window) + ;; We cannot rely on `display-message-or-buffer' returning the right + ;; window. See URL `https://github.com/flycheck/flycheck/issues/1643'. + (-when-let ((buf (get-buffer flycheck-error-message-buffer))) + (with-current-buffer buf + (unless (derived-mode-p 'flycheck-error-message-mode) + (flycheck-error-message-mode))))))) + +(defun flycheck-display-error-messages-unless-error-list (errors) + "Show messages of ERRORS unless the error list is visible. + +Like `flycheck-display-error-messages', but only if the error +list (see `flycheck-list-errors') is not visible in any window in +the current frame." + (unless (flycheck-get-error-list-window 'current-frame) + (flycheck-display-error-messages errors))) + +(defun flycheck-hide-error-buffer () + "Hide the Flycheck error buffer if necessary. + +Hide the error buffer if there is no error under point." + (-when-let* ((buffer (flycheck-error-message-buffer)) + (window (get-buffer-window buffer))) + (unless (flycheck-overlays-at (point)) + ;; save-selected-window prevents `quit-window' from changing the current + ;; buffer (see https://github.com/flycheck/flycheck/issues/648). + (save-selected-window + (quit-window nil window))))) + + +;;; Working with errors +(defun flycheck-copy-errors-as-kill (pos &optional formatter) + "Copy each error at POS into kill ring, using FORMATTER. + +FORMATTER is a function to turn an error into a string, +defaulting to `flycheck-error-message'. + +Interactively, use `flycheck-error-format-message-and-id' as +FORMATTER with universal prefix arg, and `flycheck-error-id' with +normal prefix arg, i.e. copy the message and the ID with +universal prefix arg, and only the id with normal prefix arg." + (interactive (list (point) + (pcase current-prefix-arg + ((pred not) #'flycheck-error-message) + ((pred consp) #'flycheck-error-format-message-and-id) + (_ #'flycheck-error-id)))) + (let ((messages (delq nil (seq-map (or formatter #'flycheck-error-message) + (flycheck-overlay-errors-at pos))))) + (when messages + (seq-do #'kill-new (reverse messages)) + (message (string-join messages "\n"))))) + +(defun flycheck-explain-error-at-point () + "Display an explanation for the first explainable error at point. + +The first explainable error at point is the first error at point +with a non-nil `:error-explainer' function defined in its +checker. The `:error-explainer' function is then called with +this error to produce the explanation to display." + (interactive) + (-when-let* ((first-error + ;; Get the first error at point that has an `error-explainer'. + (seq-find (lambda (error) + (flycheck-checker-get + (flycheck-error-checker error) 'error-explainer)) + (flycheck-overlay-errors-at (point)))) + (explainer + (flycheck-checker-get (flycheck-error-checker first-error) + 'error-explainer)) + (explanation (funcall explainer first-error))) + (flycheck-display-error-explanation explanation))) + +(defconst flycheck-explain-error-buffer "*Flycheck error explanation*" + "The name of the buffer to show error explanations.") + +(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 `source `source-inplace) ,suffix) + (stringp suffix)) + ((or `temporary-directory `temporary-file-name) t) + (`null-device t) + (`(config-file ,option-name ,config-file-var) + (and (stringp option-name) + (symbolp config-file-var))) + (`(config-file ,option-name ,config-file-var ,prepender) + (and (stringp option-name) + (symbolp config-file-var) + (symbolp prepender))) + (`(,(or `option `option-list) ,option-name ,option-var) + (and (stringp option-name) + (symbolp option-var))) + (`(,(or `option `option-list) ,option-name ,option-var ,prepender) + (and (stringp option-name) + (symbolp option-var) + (symbolp prepender))) + (`(,(or `option `option-list) ,option-name ,option-var ,prepender ,filter) + (and (stringp option-name) + (symbolp option-var) + (symbolp prepender) + (symbolp filter))) + (`(option-flag ,option-name ,option-var) + (and (stringp option-name) + (symbolp option-var))) + (`(eval ,_) t) + (_ nil))) + +(defun flycheck-compute-working-directory (checker) + "Get the default working directory for CHECKER. + +Compute the value of `default-directory' for the invocation of +the syntax checker command, by calling the function in the +`working-directory' property of CHECKER, with CHECKER as sole +argument, and returning its value. Signal an error if the +function returns a non-existing working directory. + +If the property is undefined or if the function returns nil +return the `default-directory' of the current buffer." + (let* ((def-directory-fn (flycheck-checker-get checker 'working-directory)) + (directory (or (and def-directory-fn + (funcall def-directory-fn checker)) + ;; Default to the `default-directory' of the current + ;; buffer + default-directory))) + (unless (file-exists-p directory) + (error ":working-directory %s of syntax checker %S does not exist" + directory checker)) + directory)) + +;;;###autoload +(defun flycheck-define-command-checker (symbol docstring &rest properties) + "Define SYMBOL as syntax checker to run a command. + +Define SYMBOL as generic syntax checker via +`flycheck-define-generic-checker', which uses an external command +to check the buffer. SYMBOL and DOCSTRING are the same as for +`flycheck-define-generic-checker'. + +In addition to the properties understood by +`flycheck-define-generic-checker', the following PROPERTIES +constitute a command syntax checker. Unless otherwise noted, all +properties are mandatory. Note that the default `:error-filter' +of command checkers is `flycheck-sanitize-errors'. + +`:command COMMAND' + The command to run for syntax checking. + + COMMAND is a list of the form `(EXECUTABLE [ARG ...])'. + + EXECUTABLE is a string with the executable of this syntax + checker. It can be overridden with the variable + `flycheck-SYMBOL-executable'. Note that this variable is + NOT implicitly defined by this function. Use + `flycheck-def-executable-var' to define this variable. + + Each ARG is an argument to the executable, either as string, + or as special symbol or form for + `flycheck-substitute-argument', which see. + +`:error-patterns PATTERNS' + A list of patterns to parse the output of the `:command'. + + Each ITEM in PATTERNS is a list `(LEVEL SEXP ...)', where + LEVEL is a Flycheck error level (see + `flycheck-define-error-level'), followed by one or more RX + `SEXP's which parse an error of that level and extract line, + column, file name and the message. + + See `rx' for general information about RX, and + `flycheck-rx-to-string' for some special RX forms provided + by Flycheck. + + All patterns are applied in the order of declaration to the + whole output of the syntax checker. Output already matched + by a pattern will not be matched by subsequent patterns. In + other words, the first pattern wins. + + This property is optional. If omitted, however, an + `:error-parser' is mandatory. + +`:error-parser FUNCTION' + A function to parse errors with. + + The function shall accept three arguments OUTPUT CHECKER + BUFFER. OUTPUT is the syntax checker output as string, + CHECKER the syntax checker that was used, and BUFFER a + buffer object representing the checked buffer. The function + must return a list of `flycheck-error' objects parsed from + OUTPUT. + + This property is optional. If omitted, it defaults to + `flycheck-parse-with-patterns'. In this case, + `:error-patterns' is mandatory. + +`:standard-input t' + Whether to send the buffer contents on standard input. + + If this property is given and has a non-nil value, send the + contents of the buffer on standard input. + + Defaults to nil. + +Note that you may not give `:start', `:interrupt', and +`:print-doc' for a command checker. You can give a custom +`:verify' function, though, whose results will be appended to the +default `:verify' function of command checkers." + (declare (indent 1) + (doc-string 2)) + (dolist (prop '(:start :interrupt :print-doc)) + (when (plist-get properties prop) + (error "%s not allowed in definition of command syntax checker %s" + prop symbol))) + + (unless (plist-get properties :error-filter) + ;; Default to `flycheck-sanitize-errors' as error filter + (setq properties (plist-put properties :error-filter + #'flycheck-sanitize-errors))) + (let ((verify-fn (plist-get properties :verify))) + (setq properties + (plist-put properties :verify + (lambda (checker) + (append (flycheck-verify-command-checker checker) + (and verify-fn + (funcall verify-fn checker))))))) + + (let ((command (plist-get properties :command)) + (patterns (plist-get properties :error-patterns)) + (parser (or (plist-get properties :error-parser) + #'flycheck-parse-with-patterns)) + (enabled (plist-get properties :enabled)) + (standard-input (plist-get properties :standard-input))) + (unless command + (error "Missing :command in syntax checker %s" symbol)) + (unless (stringp (car command)) + (error "Command executable for syntax checker %s must be a string: %S" + symbol (car command))) + (dolist (arg (cdr command)) + (unless (flycheck-command-argument-p arg) + (error "Invalid command argument %S in syntax checker %s" arg symbol))) + (when (and (eq parser 'flycheck-parse-with-patterns) + (not patterns)) + (error "Missing :error-patterns in syntax checker %s" symbol)) + + (setq properties + ;; Automatically disable command checkers if the executable does not + ;; exist. + (plist-put properties :enabled + (lambda () + (and (flycheck-find-checker-executable symbol) + (flycheck-temp-files-writable-p symbol) + (or (not enabled) (funcall enabled)))))) + + (apply #'flycheck-define-generic-checker symbol docstring + :start #'flycheck-start-command-checker + :interrupt #'flycheck-interrupt-command-checker + :print-doc #'flycheck-command-checker-print-doc + properties) + + ;; Pre-compile all errors patterns into strings, so that we don't need to do + ;; that on each error parse + (let ((patterns (seq-map (lambda (p) + (cons (flycheck-rx-to-string `(and ,@(cdr p)) + 'no-group) + (car p))) + patterns))) + (pcase-dolist (`(,prop . ,value) + `((command . ,command) + (error-parser . ,parser) + (error-patterns . ,patterns) + (standard-input . ,standard-input))) + (setf (flycheck-checker-get symbol prop) value))))) + +(eval-and-compile + ;; Make this function available during byte-compilation, since we need it + ;; at macro expansion of `flycheck-def-executable-var'. + (defun flycheck-checker-executable-variable (checker) + "Get the executable variable of CHECKER. + +The executable variable is named `flycheck-CHECKER-executable'." + (intern (format "flycheck-%s-executable" checker)))) + +(defun flycheck-checker-default-executable (checker) + "Get the default executable of CHECKER." + (car (flycheck-checker-get checker 'command))) + +(defun flycheck-checker-executable (checker) + "Get the command executable of CHECKER. + +The executable is either the value of the variable +`flycheck-CHECKER-executable', or the default executable given in +the syntax checker definition, if the variable is nil." + (let ((var (flycheck-checker-executable-variable checker))) + (or (and (boundp var) (symbol-value var)) + (flycheck-checker-default-executable checker)))) + +(defun flycheck-find-checker-executable (checker) + "Get the full path of the executable of CHECKER. + +Return the full absolute path to the executable of CHECKER, or +nil if the executable does not exist." + (funcall flycheck-executable-find (flycheck-checker-executable checker))) + +(defun flycheck-checker-arguments (checker) + "Get the command arguments of CHECKER." + (cdr (flycheck-checker-get checker 'command))) + +(defun flycheck-substitute-argument (arg checker) + "Substitute ARG for CHECKER. + +Return a list of real arguments for the executable of CHECKER, +substituted for the symbolic argument ARG. Single arguments, +e.g. if ARG is a literal strings, are wrapped in a list. + +ARG may be one of the following forms: + +STRING + Return ARG unchanged. + +`source', `source-inplace' + Create a temporary file to check and return its path. With + `source-inplace' create the temporary file in the same + directory as the original file. The value of + `flycheck-temp-prefix' is used as prefix of the file name. + + With `source', try to retain the non-directory component of + the buffer's file name in the temporary file. + + `source' is the preferred way to pass the input file to a + syntax checker. `source-inplace' should only be used if the + syntax checker needs other files from the source directory, + such as include files in C. + +`(source SUFFIX)', `(source-inplace SUFFIX)' + Like `source' and `source-inplace', but ensure generated + file names end with the given suffix. Use this when the + checker requires that file names on its command line have a + certain suffix (file extension). + +`source-original' + Return the path of the actual file to check, or an empty + string if the buffer has no file name. + + Note that the contents of the file may not be up to date + with the contents of the buffer to check. Do not use this + as primary input to a checker, unless absolutely necessary. + + When using this symbol as primary input to the syntax + checker, add `flycheck-buffer-saved-p' to the `:predicate'. + +`temporary-directory' + Create a unique temporary directory and return its path. + +`temporary-file-name' + Return a unique temporary filename. The file is *not* + created. + + To ignore the output of syntax checkers, try `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 ,suffix) + (list (flycheck-save-buffer-to-temp + (lambda (filename) (flycheck-temp-file-system filename suffix))))) + (`(source-inplace ,suffix) + (list (flycheck-save-buffer-to-temp + (lambda (filename) (flycheck-temp-file-inplace filename suffix))))) + (`source-original (list (or (buffer-file-name) ""))) + (`temporary-directory (list (flycheck-temp-dir-system))) + (`temporary-file-name + (let ((directory (flycheck-temp-dir-system))) + (list (make-temp-name (expand-file-name "flycheck" directory))))) + (`null-device (list null-device)) + (`(config-file ,option-name ,file-name-var) + (-when-let* ((value (symbol-value file-name-var)) + (file-name (flycheck-locate-config-file value checker))) + (flycheck-prepend-with-option option-name (list file-name)))) + (`(config-file ,option-name ,file-name-var ,prepend-fn) + (-when-let* ((value (symbol-value file-name-var)) + (file-name (flycheck-locate-config-file value checker))) + (flycheck-prepend-with-option option-name (list file-name) prepend-fn))) + (`(option ,option-name ,variable) + (-when-let (value (symbol-value variable)) + (unless (stringp value) + (error "Value %S of %S for option %s is not a string" + value variable option-name)) + (flycheck-prepend-with-option option-name (list value)))) + (`(option ,option-name ,variable ,prepend-fn) + (-when-let (value (symbol-value variable)) + (unless (stringp value) + (error "Value %S of %S for option %s is not a string" + value variable option-name)) + (flycheck-prepend-with-option option-name (list value) prepend-fn))) + (`(option ,option-name ,variable ,prepend-fn ,filter) + (-when-let (value (funcall filter (symbol-value variable))) + (unless (stringp value) + (error "Value %S of %S (filter: %S) for option %s is not a string" + value variable filter option-name)) + (flycheck-prepend-with-option option-name (list value) prepend-fn))) + (`(option-list ,option-name ,variable) + (let ((value (symbol-value variable))) + (unless (and (listp value) (seq-every-p #'stringp value)) + (error "Value %S of %S for option %S is not a list of strings" + value variable option-name)) + (flycheck-prepend-with-option option-name value))) + (`(option-list ,option-name ,variable ,prepend-fn) + (let ((value (symbol-value variable))) + (unless (and (listp value) (seq-every-p #'stringp value)) + (error "Value %S of %S for option %S is not a list of strings" + value variable option-name)) + (flycheck-prepend-with-option option-name value prepend-fn))) + (`(option-list ,option-name ,variable ,prepend-fn ,filter) + (let ((value (delq nil (seq-map filter (symbol-value variable))))) + (unless (and (listp value) (seq-every-p #'stringp value)) + (error "Value %S of %S for option %S is not a list of strings" + value variable option-name)) + (flycheck-prepend-with-option option-name value prepend-fn))) + (`(option-flag ,option-name ,variable) + (when (symbol-value variable) + (list option-name))) + (`(eval ,form) + (let ((result (eval form))) + (cond + ((and (listp result) (seq-every-p #'stringp result)) result) + ((stringp result) (list result)) + (t (error "Invalid result from evaluation of %S: %S" form result))))) + (_ (error "Unsupported argument %S" arg)))) + +(defun flycheck-checker-substituted-arguments (checker) + "Get the substituted arguments of a CHECKER. + +Substitute each argument of CHECKER using +`flycheck-substitute-argument'. This replaces any special +symbols in the command." + (apply #'append + (seq-map (lambda (arg) (flycheck-substitute-argument arg checker)) + (flycheck-checker-arguments checker)))) + +(defun flycheck--process-send-buffer-contents-chunked (process) + "Send contents of current buffer to PROCESS in small batches. + +Send the entire buffer to the standard input of PROCESS in chunks +of 4096 characters. Chunking is done in Emacs Lisp, hence this +function is probably far less efficient than +`send-process-region'. Use only when required." + (let ((from (point-min))) + (while (< from (point-max)) + (let ((to (min (+ from 4096) (point-max)))) + (process-send-region process from to) + (setq from to))))) + +(defvar flycheck-chunked-process-input + ;; Chunk process output on Windows to work around + ;; https://github.com/flycheck/flycheck/issues/794 and + ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22344. The presence of + ;; `w32-pipe-buffer-size' denotes an Emacs version (> Emacs 25.1) where pipe + ;; writes on Windows are fixed. + ;; + ;; TODO: Remove option and chunking when dropping Emacs 24 support, see + ;; https://github.com/flycheck/flycheck/issues/856 + (and (eq system-type 'windows-nt) (not (boundp 'w32-pipe-buffer-size))) + "If non-nil send process input in small chunks. + +If this variable is non-nil `flycheck-process-send-buffer' sends +buffer contents in small chunks. + +Defaults to nil, except on Windows to work around Emacs bug +#22344.") + +(defun flycheck-process-send-buffer (process) + "Send all contents of current buffer to PROCESS. + +Sends all contents of the current buffer to the standard input of +PROCESS, and terminates standard input with EOF. + +If `flycheck-chunked-process-input' is non-nil, send buffer +contents in chunks via +`flycheck--process-send-buffer-contents-chunked', which see. +Otherwise use `process-send-region' to send all contents at once +and rely on Emacs' own buffering and chunking." + (save-restriction + (widen) + (if flycheck-chunked-process-input + (flycheck--process-send-buffer-contents-chunked process) + (process-send-region process (point-min) (point-max)))) + (process-send-eof process)) + +(defun flycheck--wrap-command (prog args) + "Wrap PROG and ARGS using `flycheck-command-wrapper-function'." + ;; We don't call `flycheck-executable-find' on the output of the wrapper + ;; function, since it might not expect it (an executable-find function + ;; designed to find binaries in a sandbox could get confused if we asked it + ;; about the sandboxing program itself). + (funcall flycheck-command-wrapper-function (cons prog args))) + +(defun flycheck-start-command-checker (checker callback) + "Start a command CHECKER with CALLBACK." + (let (process) + (condition-case err + (let* ((program (flycheck-find-checker-executable checker)) + (args (flycheck-checker-substituted-arguments checker)) + (command (flycheck--wrap-command program args)) + (sentinel-events nil) + ;; Use pipes to receive output from the syntax checker. They are + ;; more efficient and more robust than PTYs, which Emacs uses by + ;; default, and since we don't need any job control features, we + ;; can easily use pipes. + (process-connection-type nil)) + ;; We pass do not associate the process with any buffer, by + ;; passing nil for the BUFFER argument of `start-process'. + ;; Instead, we just remember the buffer being checked in a + ;; process property (see below). This neatly avoids all + ;; side-effects implied by attached a process to a buffer, which + ;; may cause conflicts with other packages. + ;; + ;; See https://github.com/flycheck/flycheck/issues/298 for an + ;; example for such a conflict. + (setq process (apply 'start-process (format "flycheck-%s" checker) + nil command)) + ;; Process sentinels can be called while sending input to the process. + ;; We want to record errors raised by process-send before calling + ;; `flycheck-handle-signal', so initially just accumulate events. + (setf (process-sentinel process) + (lambda (_ event) (push event sentinel-events))) + (setf (process-filter process) #'flycheck-receive-checker-output) + (set-process-query-on-exit-flag process nil) + ;; Remember the syntax checker, the buffer and the callback + (process-put process 'flycheck-checker checker) + (process-put process 'flycheck-callback callback) + (process-put process 'flycheck-buffer (current-buffer)) + ;; The default directory is bound in the `flycheck-syntax-check-start' + ;; function. + (process-put process 'flycheck-working-directory default-directory) + ;; Track the temporaries created by argument substitution in the + ;; process itself, to get rid of the global state ASAP. + (process-put process 'flycheck-temporaries flycheck-temporaries) + (setq flycheck-temporaries nil) + ;; Send the buffer to the process on standard input, if enabled. + (when (flycheck-checker-get checker 'standard-input) + (condition-case err + (flycheck-process-send-buffer process) + ;; Some checkers exit before reading all input, causing errors + ;; such as a `file-error' for a closed pipe, or a plain “no longer + ;; connected to pipe; closed it” error for a disconnection. We + ;; report them if needed in `flycheck-finish-checker-process' (see + ;; `https://github.com/flycheck/flycheck/issues/1278'). + (error (process-put process 'flycheck-error err)))) + ;; Set the actual sentinel and process any events that might have + ;; happened while we were sending input. + (setf (process-sentinel process) #'flycheck-handle-signal) + (dolist (event (nreverse sentinel-events)) + (flycheck-handle-signal process event)) + ;; Return the process. + process) + (error + ;; In case of error, clean up our resources, and report the error back to + ;; Flycheck. + (flycheck-safe-delete-temporaries) + (when process + ;; No need to explicitly delete the temporary files of the process, + ;; because deleting runs the sentinel, which will delete them anyway. + (delete-process process)) + (signal (car err) (cdr err)))))) + +(defun flycheck-interrupt-command-checker (_checker process) + "Interrupt a PROCESS." + ;; Deleting the process always triggers the sentinel, which does the cleanup + (when process + (delete-process process))) + +(defun flycheck-command-checker-print-doc (checker) + "Print additional documentation for a command CHECKER." + (let ((executable (flycheck-checker-default-executable checker)) + (config-file-var (flycheck-checker-get checker 'config-file-var)) + (option-vars (seq-sort #'string< + (flycheck-checker-get checker 'option-vars)))) + (princ "\n") + + (let ((doc-start (with-current-buffer standard-output (point-max)))) + ;; Track the start of our documentation so that we can re-indent it + ;; properly + (princ " This syntax checker executes \"") + (princ executable) + (princ "\"") + (when config-file-var + (princ ", using a configuration file from `") + (princ (symbol-name config-file-var)) + (princ "'")) + (princ ". The executable can be overridden with `") + (princ (symbol-name (flycheck-checker-executable-variable checker))) + (princ "'.") + + (with-current-buffer standard-output + (save-excursion + (fill-region-as-paragraph doc-start (point-max))))) + (princ "\n") + (when option-vars + (princ + "\n This syntax checker can be configured with these options:\n\n") + (dolist (var option-vars) + (princ (format " * `%s'\n" var)))))) + +(defun flycheck-verify-command-checker (checker) + "Verify a command CHECKER in the current buffer. + +Return a list of `flycheck-verification-result' objects for +CHECKER." + (let ((executable (flycheck-find-checker-executable checker)) + (config-file-var (flycheck-checker-get checker 'config-file-var))) + `( + ,(flycheck-verification-result-new + :label "executable" + :message (if executable (format "Found at %s" executable) "Not found") + :face (if executable 'success '(bold error))) + ,@(when config-file-var + (let* ((value (symbol-value config-file-var)) + (path (and value (flycheck-locate-config-file value checker)))) + (list (flycheck-verification-result-new + :label "configuration file" + :message (if path (format "Found at %S" path) "Not found") + :face (if path 'success 'warning))))) + ,@(when (not (flycheck-temp-files-writable-p checker)) + (list (flycheck-verification-result-new + :label "temp directory" + :message (format "%s is not writable" + (flycheck-temp-directory checker)) + :face 'error)))))) + + +;;; Process management for command syntax checkers +(defun flycheck-receive-checker-output (process output) + "Receive a syntax checking PROCESS OUTPUT." + (push output (process-get process 'flycheck-pending-output))) + +(defun flycheck-get-output (process) + "Get the complete output of PROCESS." + (with-demoted-errors "Error while retrieving process output: %S" + (let ((pending-output (process-get process 'flycheck-pending-output))) + (apply #'concat (nreverse pending-output))))) + +(defun flycheck-handle-signal (process _event) + "Handle a signal from the syntax checking PROCESS. + +_EVENT is ignored." + (when (memq (process-status process) '(signal exit)) + (let ((files (process-get process 'flycheck-temporaries)) + (buffer (process-get process 'flycheck-buffer)) + (callback (process-get process 'flycheck-callback)) + (cwd (process-get process 'flycheck-working-directory)) + (err (process-get process 'flycheck-error))) + ;; Delete the temporary files + (seq-do #'flycheck-safe-delete files) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (condition-case err + (pcase (process-status process) + (`signal + (funcall callback 'interrupted)) + (`exit + (flycheck-finish-checker-process + (process-get process 'flycheck-checker) + (or err (process-exit-status process)) + files + (flycheck-get-output process) callback cwd))) + ((debug error) + (funcall callback 'errored (error-message-string err))))))))) + +(defun flycheck-finish-checker-process + (checker exit-status files output callback cwd) + "Finish a checker process from CHECKER with EXIT-STATUS. + +EXIT-STATUS can be a number or an arbitrary form (if it is not 0, +a `suspicious' status is reported to CALLBACK). + +FILES is a list of files given as input to the checker. OUTPUT +is the output of the syntax checker. CALLBACK is the status +callback to use for reporting. + +Parse the OUTPUT and report an appropriate error status. + +Resolve all errors in OUTPUT using CWD as working directory." + (let ((errors (flycheck-parse-output output checker (current-buffer)))) + (when (and (not (equal exit-status 0)) (null errors)) + ;; Warn about a suspicious result from the syntax checker. We do right + ;; after parsing the errors, before filtering, because a syntax checker + ;; might report errors from other files (e.g. includes) even if there + ;; are no errors in the file being checked. + (funcall callback 'suspicious + (format "Flycheck checker %S returned %S, but \ +its output contained no errors: %s\nTry installing a more \ +recent version of %S, and please open a bug report if the issue \ +persists in the latest release. Thanks!" checker exit-status +output checker))) + (funcall callback 'finished + ;; Fix error file names, by substituting them backwards from the + ;; temporaries. + (seq-map (lambda (e) (flycheck-fix-error-filename e files cwd)) + errors)))) + + +;;; Executables of command checkers. +(defmacro flycheck-def-executable-var (checker default-executable) + "Define the executable variable for CHECKER. + +DEFAULT-EXECUTABLE is the default executable. It is only used in +the docstring of the variable. + +The variable is defined with `defcustom' in the +`flycheck-executables' group. It's also defined to be risky as +file-local variable, to avoid arbitrary executables being used +for syntax checking." + (let ((executable-var (flycheck-checker-executable-variable checker))) + `(progn + (defcustom ,executable-var nil + ,(format "The executable of the %s syntax checker. + +Either a string containing the name or the path of the +executable, or nil to use the default executable from the syntax +checker declaration. + +The default executable is %S." checker default-executable) + :type '(choice (const :tag "Default executable" nil) + (string :tag "Name or path")) + :group 'flycheck-executables + :risky t)))) + +(defun flycheck-set-checker-executable (checker &optional executable) + "Set the executable of CHECKER in the current buffer. + +CHECKER is a syntax checker symbol. EXECUTABLE is a string with +the name of an executable or the path to an executable file, which +is to be used as executable for CHECKER. If omitted or nil, +reset the executable of CHECKER. + +Interactively, prompt for a syntax checker and an executable +file, and set the executable of the selected syntax checker. +With prefix arg, prompt for a syntax checker only, and reset the +executable of the select checker to the default. + +Set the executable variable of CHECKER, that is, +`flycheck-CHECKER-executable' to EXECUTABLE. Signal +`user-error', if EXECUTABLE does not denote a command or an +executable file. + +This command is intended for interactive use only. In Lisp, just +`let'-bind the corresponding variable, or set it directly. Use +`flycheck-checker-executable-variable' to obtain the executable +variable symbol for a syntax checker." + (declare (interactive-only "Set the executable variable directly instead")) + (interactive + (let* ((checker (flycheck-read-checker "Syntax checker: ")) + (default-executable (flycheck-checker-default-executable checker)) + (executable (if current-prefix-arg + nil + (read-file-name "Executable: " nil default-executable + nil nil flycheck-executable-find)))) + (list checker executable))) + (when (and executable (not (funcall flycheck-executable-find executable))) + (user-error "%s is no executable" executable)) + (let ((variable (flycheck-checker-executable-variable checker))) + (set (make-local-variable variable) executable))) + + +;;; Configuration files and options for command checkers +(defun flycheck-register-config-file-var (var checkers) + "Register VAR as config file var for CHECKERS. + +CHECKERS is a single syntax checker or a list thereof." + (when (symbolp checkers) + (setq checkers (list checkers))) + (dolist (checker checkers) + (setf (flycheck-checker-get checker 'config-file-var) var))) + +;;;###autoload +(defmacro flycheck-def-config-file-var (symbol checker &optional file-name + &rest custom-args) + "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME. + +SYMBOL is declared as customizable variable using `defcustom', to +provide configuration files for the given syntax CHECKER. +CUSTOM-ARGS are forwarded to `defcustom'. + +FILE-NAME is the initial value of the new variable. If omitted, +the default value is nil. It can be either a string or a list of +strings. + +Use this together with the `config-file' form in the `:command' +argument to `flycheck-define-checker'." + (declare (indent 3)) + `(progn + (defcustom ,symbol ,file-name + ,(format "Configuration file for `%s'. + +If set to a string, locate the configuration file using the +functions from `flycheck-locate-config-file-functions'. If the +file is found pass it to the syntax checker as configuration +file. + +If no configuration file is found, or if this variable is set to +nil, invoke the syntax checker without a configuration file. + +Use this variable as file-local variable if you need a specific +configuration file for a buffer." checker) + :type '(choice (const :tag "No configuration file" nil) + (string :tag "File name or path") + (repeat :tag "File names or paths" string)) + :safe #'flycheck-string-or-string-list-p + :group 'flycheck-config-files + ,@custom-args) + (flycheck-register-config-file-var ',symbol ',checker))) + +(defun flycheck-locate-config-file (filenames checker) + "Locate the configuration file for CHECKER, based on FILENAMES. + +FILENAMES can be either a single file, or a list. Each filename +is passed to all `flycheck-locate-config-file-functions', until +one returns non-nil. + +Return the absolute path of the configuration file, or nil if no +configuration file was found." + (when (stringp filenames) + (setq filenames (list filenames))) + (let ((config-file nil)) + (while (and filenames (null config-file)) + (setq config-file (run-hook-with-args-until-success + 'flycheck-locate-config-file-functions + (pop filenames) checker))) + (when (and config-file (file-exists-p config-file)) + config-file))) + +(defun flycheck-locate-config-file-by-path (filepath _checker) + "Locate a configuration file by a FILEPATH. + +If FILEPATH is a contains a path separator, expand it against the +default directory and return it if it points to an existing file. +Otherwise return nil. + +_CHECKER is ignored." + ;; If the path is just a plain file name, skip it. + (unless (string= (file-name-nondirectory filepath) filepath) + (let ((file-name (expand-file-name filepath))) + (and (file-exists-p file-name) file-name)))) + +(defun flycheck-locate-config-file-ancestor-directories (filename _checker) + "Locate a configuration FILENAME in ancestor directories. + +If the current buffer has a file name, search FILENAME in the +directory of the current buffer and all ancestors thereof (see +`locate-dominating-file'). If the file is found, return its +absolute path. Otherwise return nil. + +_CHECKER is ignored." + (-when-let* ((basefile (buffer-file-name)) + (directory (locate-dominating-file basefile filename))) + (expand-file-name filename directory))) + +(defun flycheck-locate-config-file-home (filename _checker) + "Locate a configuration FILENAME in the home directory. + +Return the absolute path, if FILENAME exists in the user's home +directory, or nil otherwise." + (let ((path (expand-file-name filename "~"))) + (when (file-exists-p path) + path))) + +(seq-do (apply-partially #'custom-add-frequent-value + 'flycheck-locate-config-file-functions) + '(flycheck-locate-config-file-by-path + flycheck-locate-config-file-ancestor-directories + flycheck-locate-config-file-home)) + +(defun flycheck-register-option-var (var checkers) + "Register an option VAR with CHECKERS. + +VAR is an option symbol, and CHECKERS a syntax checker symbol or +a list thereof. Register VAR with all CHECKERS so that it +appears in the help output." + (when (symbolp checkers) + (setq checkers (list checkers))) + (dolist (checker checkers) + (cl-pushnew var (flycheck-checker-get checker 'option-vars)))) + +;;;###autoload +(defmacro flycheck-def-option-var (symbol init-value checkers docstring + &rest custom-args) + "Define SYMBOL as option variable with INIT-VALUE for CHECKER. + +SYMBOL is declared as customizable variable using `defcustom', to +provide an option for the given syntax CHECKERS (a checker or a +list of checkers). INIT-VALUE is the initial value of the +variable, and DOCSTRING is its docstring. CUSTOM-ARGS are +forwarded to `defcustom'. + +Use this together with the `option', `option-list' and +`option-flag' forms in the `:command' argument to +`flycheck-define-checker'." + (declare (indent 3) + (doc-string 4)) + `(progn + (defcustom ,symbol ,init-value + ,(concat docstring " + +This variable is an option for the following syntax checkers: + +" + (mapconcat (lambda (c) (format " - `%s'" c)) + (if (symbolp checkers) (list checkers) checkers) + "\n")) + :group 'flycheck-options + ,@custom-args) + (flycheck-register-option-var ',symbol ',checkers))) + +(defun flycheck-option-int (value) + "Convert an integral option VALUE to a string. + +If VALUE is nil, return nil. Otherwise return VALUE converted to +a string." + (and value (number-to-string value))) + +(defun flycheck-option-symbol (value) + "Convert a symbol option VALUE to string. + +If VALUE is nil return nil. Otherwise return VALUE converted to +a string." + (and value (symbol-name value))) + +(defun flycheck-option-comma-separated-list (value &optional separator filter) + "Convert VALUE into a list separated by SEPARATOR. + +SEPARATOR is a string to separate items in VALUE, defaulting to +\",\". FILTER is an optional function, which takes a single +argument and returns either a string or nil. + +If VALUE is a list, apply FILTER to each item in VALUE, remove +all nil items, and return a single string of all remaining items +separated by SEPARATOR. + +Otherwise, apply FILTER to VALUE and return the result. +SEPARATOR is ignored in this case." + (let ((filter (or filter #'identity)) + (separator (or separator ","))) + (if (listp value) + (-when-let (value (delq nil (seq-map filter value))) + (string-join value separator)) + (funcall filter value)))) + +(defmacro flycheck-def-args-var (symbol checkers &rest custom-args) + "Define SYMBOL as argument variable for CHECKERS. + +SYMBOL is declared as customizable, risky and buffer-local +variable using `defcustom' to provide an option for arbitrary +arguments for the given syntax CHECKERS (either a single checker +or a list of checkers). CUSTOM-ARGS is forwarded to `defcustom'. + +Use the `eval' form to splice this variable into the +`:command'." + (declare (indent 2)) + `(flycheck-def-option-var ,symbol nil ,checkers + "A list of additional command line arguments. + +The value of this variable is a list of strings with additional +command line arguments." + :risky t + :type '(repeat (string :tag "Argument")) + ,@custom-args)) + + +;;; Command syntax checkers as compile commands +(defun flycheck-checker-pattern-to-error-regexp (pattern) + "Convert PATTERN into an error regexp for compile.el. + +Return a list representing PATTERN, suitable as element in +`compilation-error-regexp-alist'." + (let* ((regexp (car pattern)) + (level (cdr pattern)) + (level-no (flycheck-error-level-compilation-level level))) + `(,regexp 1 (2 . 6) (3 . 7) ,level-no))) + +(defun flycheck-checker-compilation-error-regexp-alist (checker) + "Convert error patterns of CHECKER for use with compile.el. + +Return an alist of all error patterns of CHECKER, suitable for +use with `compilation-error-regexp-alist'." + (seq-map #'flycheck-checker-pattern-to-error-regexp + (flycheck-checker-get checker 'error-patterns))) + +(defun flycheck--substitute-shell-command-argument (arg checker) + "Substitute ARG for CHECKER. + +Like `flycheck-substitute-argument', except for source, +source-inplace, and source-original." + (if (memq arg '(source source-inplace source-original)) + (list buffer-file-name) + (flycheck-substitute-argument arg checker))) + +(defun flycheck--checker-substituted-shell-command-arguments (checker) + "Get the substituted arguments of a CHECKER to run as a shell command. + +Substitute each argument of CHECKER using +`flycheck-substitute-shell-command-argument'." + (apply #'append + (seq-map (lambda (arg) + (flycheck--substitute-shell-command-argument arg checker)) + (flycheck-checker-arguments checker)))) + +(defun flycheck-checker-shell-command (checker) + "Get a shell command for CHECKER. + +Perform substitution in the arguments of CHECKER, but with +`flycheck--substitute-shell-command-argument'. + +Return the command of CHECKER as single string, suitable for +shell execution." + ;; Note: Do NOT use `combine-and-quote-strings' here. Despite it's name it + ;; does not properly quote shell arguments, and actually breaks for special + ;; characters. See https://github.com/flycheck/flycheck/pull/522 + (let* ((args (flycheck--checker-substituted-shell-command-arguments checker)) + (program + (or (flycheck-find-checker-executable checker) + (user-error "Cannot find `%s' using `flycheck-executable-find'" + (flycheck-checker-executable checker)))) + (wrapped (flycheck--wrap-command program args)) + (abs-prog + ;; The executable path returned by `flycheck-command-wrapper-function' + ;; may not be absolute, so expand it here. See URL + ;; `https://github.com/flycheck/flycheck/issues/1461'. + (or (executable-find (car wrapped)) + (user-error "Cannot find `%s' using `executable-find'" + (car wrapped)))) + (command (mapconcat #'shell-quote-argument + (cons abs-prog (cdr wrapped)) " "))) + (if (flycheck-checker-get checker 'standard-input) + ;; If the syntax checker expects the source from standard input add an + ;; appropriate shell redirection + (concat command " < " (shell-quote-argument (buffer-file-name))) + command))) + +(defun flycheck-compile-name (_name) + "Get a name for a Flycheck compilation buffer. + +_NAME is ignored." + (format "*Flycheck %s*" (buffer-file-name))) + +(defun flycheck-compile (checker) + "Run CHECKER via `compile'. + +CHECKER must be a valid syntax checker. Interactively, prompt +for a syntax checker to run. + +Instead of highlighting errors in the buffer, this command pops +up a separate buffer with the entire output of the syntax checker +tool, just like `compile' (\\[compile])." + (interactive + (let ((default (flycheck-get-checker-for-buffer))) + (list (flycheck-read-checker "Run syntax checker as compile command: " + (when (flycheck-checker-get default 'command) + default) + 'command)))) + (unless (flycheck-valid-checker-p checker) + (user-error "%S is not a valid syntax checker" checker)) + (unless (buffer-file-name) + (user-error "Cannot compile a buffer without a backing file")) + (unless (flycheck-may-use-checker checker) + (user-error "Cannot use syntax checker %S in this buffer" checker)) + (unless (flycheck-checker-executable checker) + (user-error "Cannot run checker %S as shell command" checker)) + (save-some-buffers) + (let* ((default-directory (flycheck-compute-working-directory checker)) + (command (flycheck-checker-shell-command checker)) + (buffer (compilation-start command nil #'flycheck-compile-name))) + (with-current-buffer buffer + (setq-local compilation-error-regexp-alist + (flycheck-checker-compilation-error-regexp-alist checker))))) + + +;;; General error parsing for command checkers +(defun flycheck-parse-output (output checker buffer) + "Parse OUTPUT from CHECKER in BUFFER. + +OUTPUT is a string with the output from the checker symbol +CHECKER. BUFFER is the buffer which was checked. + +Return the errors parsed with the error patterns of CHECKER." + (funcall (flycheck-checker-get checker 'error-parser) output checker buffer)) + +(defun flycheck-fix-error-filename (err buffer-files cwd) + "Fix the file name of ERR from BUFFER-FILES. + +Resolves error file names relative to CWD directory. + +Make the file name of ERR absolute. If the absolute file name of +ERR is in BUFFER-FILES, replace it with the value of variable +`buffer-file-name'." + (flycheck-error-with-buffer err + (-when-let (filename (flycheck-error-filename err)) + (when (seq-some (apply-partially #'flycheck-same-files-p + (expand-file-name filename cwd)) + buffer-files) + (setf (flycheck-error-filename err) buffer-file-name) + (when (and buffer-file-name (flycheck-error-message err)) + (setf (flycheck-error-message err) + (replace-regexp-in-string + (regexp-quote filename) buffer-file-name + (flycheck-error-message err) 'fixed-case 'literal)))))) + err) + + +;;; Error parsers for command syntax checkers +(defun flycheck-parse-xml-region (beg end) + "Parse the xml region between BEG and END. + +Wrapper around `xml-parse-region' which transforms the return +value of this function into one compatible to +`libxml-parse-xml-region' by simply returning the first element +from the node list." + (ignore-errors (car (xml-parse-region beg end)))) + +(defun flycheck-parse-xml-region-with-fallback (beg end) + "Parse the xml region between BEG and END. + +Try parsing with libxml first; if that fails, revert to +`flycheck-parse-xml-region'. Failures can be caused by incorrect +XML (see URL `https://github.com/flycheck/flycheck/issues/1298'), +or on Windows by a missing libxml DLL with a libxml-enabled Emacs +\(see URL `https://github.com/flycheck/flycheck/issues/1330')." + ;; FIXME use `libxml-available-p' when it gets implemented. + (or (and (fboundp 'libxml-parse-xml-region) + (libxml-parse-xml-region beg end)) + (flycheck-parse-xml-region beg end))) + +(defvar flycheck-xml-parser 'flycheck-parse-xml-region-with-fallback + "Function used to parse an xml string from a region. + +The default uses libxml if available, and falls back to +`flycheck-parse-xml-region' otherwise.") + +(defun flycheck-parse-xml-string (xml) + "Parse an XML string. + +Return the document tree parsed from XML in the form `(ROOT ATTRS +BODY...)'. ROOT is a symbol identifying the name of the root +element. ATTRS is an alist of the attributes of the root node. +BODY is zero or more body elements, either as strings (in case of +text nodes) or as XML nodes, in the same for as the root node." + (with-temp-buffer + (insert xml) + (funcall flycheck-xml-parser (point-min) (point-max)))) + +(defun flycheck-parse-checkstyle (output checker buffer) + "Parse Checkstyle errors from OUTPUT. + +Parse Checkstyle-like XML output. Use this error parser for +checkers that have an option to output errors in this format. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://checkstyle.sourceforge.net/' for information +about Checkstyle." + (pcase (flycheck-parse-xml-string output) + (`(checkstyle ,_ . ,file-nodes) + (let (errors) + (dolist (node file-nodes) + (pcase node + (`(file ,file-attrs . ,error-nodes) + (dolist (node error-nodes) + (pcase node + (`(error ,error-attrs . ,_) + (let-alist error-attrs + (push (flycheck-error-new-at + (flycheck-string-to-number-safe .line) + (flycheck-string-to-number-safe .column) + (pcase .severity + (`"error" 'error) + (`"warning" 'warning) + (`"info" 'info) + ;; Default to error for unknown .severity + (_ 'error)) + .message + :checker checker :id .source + :buffer buffer + :filename (cdr (assq 'name file-attrs))) + errors)))))))) + (nreverse errors))))) + +(defun flycheck-parse-cppcheck (output checker buffer) + "Parse Cppcheck errors from OUTPUT. + +Parse Cppcheck XML v2 output. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://cppcheck.sourceforge.net/' for more information +about Cppcheck." + (pcase (flycheck-parse-xml-string output) + (`(results ,_ . ,body) + (let (errors) + (dolist (node body) + (pcase node + (`(errors ,_ . ,error-nodes) + (dolist (node error-nodes) + (pcase node + (`(error ,error-attrs . ,loc-nodes) + (let ((id (cdr (assq 'id error-attrs))) + (message (cdr (assq 'verbose error-attrs))) + (level (pcase (cdr (assq 'severity error-attrs)) + (`"error" 'error) + (`"style" 'info) + (`"information" 'info) + (_ 'warning)))) + (dolist (node loc-nodes) + (pcase node + (`(location ,loc-attrs . ,_) + (let-alist loc-attrs + (push (flycheck-error-new-at + (flycheck-string-to-number-safe .line) + nil + level + ;; cppcheck return newline characters as "\012" + (replace-regexp-in-string "\\\\012" "\n" + message) + :id id + :checker checker + :buffer buffer + :filename .file) + errors)))))))))))) + (nreverse errors))))) + +(defun flycheck-parse-phpmd (output checker buffer) + "Parse phpmd errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://phpmd.org/' for more information about phpmd." + (pcase (flycheck-parse-xml-string output) + (`(pmd ,_ . ,body) + (let (errors) + (dolist (node body) + (pcase node + (`(file ,file-attrs . ,violation-nodes) + (let ((filename (cdr (assq 'name file-attrs)))) + (dolist (node violation-nodes) + (pcase node + (`(violation ,vio-attrs ,(and message (pred stringp))) + (let-alist vio-attrs + (push + (flycheck-error-new-at + (flycheck-string-to-number-safe .beginline) + nil + 'warning (string-trim message) + ;; Ignore .endline (phpmd marks giant spans as errors) + ;; :end-line (flycheck-string-to-number-safe .endline) + :id .rule + :checker checker + :buffer buffer + :filename filename) + errors))))))))) + (nreverse errors))))) + +(defun flycheck-parse-reek (output checker buffer) + "Parse Reek warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://github.com/troessner/reek' for more information +about Reek." + (let ((errors nil)) + (dolist (message (car (flycheck-parse-json output))) + (let-alist message + (dolist (line (delete-dups .lines)) + (push + (flycheck-error-new-at + line + nil + 'warning (concat .context " " .message) + :id .smell_type + :checker checker + :buffer buffer + :filename .source) + errors)))) + (nreverse errors))) + +(defun flycheck-parse-go-staticcheck (output checker buffer) + "Parse staticheck warnings from JSON OUTPUT. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://staticcheck.io/docs/formatters' for more +information about staticheck." + (let ((errors nil)) + (dolist (msg (flycheck-parse-json output)) + (let-alist msg + (push + (flycheck-error-new-at + .location.line + .location.column + (pcase .severity + (`"error" 'error) + (`"warning" 'warning) + (`"ignored" 'info) + ;; Default to warning for unknown .severity + (_ 'warning)) + .message + :id .code + :checker checker + :buffer buffer + :filename .location.file) + errors))) + (nreverse errors))) + +(defun flycheck-parse-tslint (output checker buffer) + "Parse TSLint errors from JSON OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `https://palantir.github.io/tslint/' for more information +about TSLint." + (seq-map (lambda (message) + (let-alist message + (flycheck-error-new-at + (+ 1 .startPosition.line) + (+ 1 .startPosition.character) + (pcase .ruleSeverity + ("ERROR" 'error) + ("WARNING" 'warning) + (_ 'warning)) + .failure + :id .ruleName + :checker checker + :buffer buffer + :filename .name + :end-line (+ 1 .endPosition.line) + :end-column (+ 1 .endPosition.character)))) + (car (flycheck-parse-json output)))) + +(defun flycheck-parse-rust-collect-spans (span) + "Return a list of spans contained in a SPAN object." + (let ((spans)) + (let-alist span + ;; With macro expansion errors, some spans will point to phony file names + ;; to indicate an error inside the std rust lib. We skip these spans as + ;; they won't appear in flycheck anyway. + (unless (string= .file_name "") + (push span spans)) + + ;; Macro expansion errors will have a span in the 'expansion' field, so we + ;; recursively collect it. + (if .expansion.span + (append (flycheck-parse-rust-collect-spans .expansion.span) + spans) + spans)))) + +(defun flycheck-parse-rustc-diagnostic (diagnostic checker buffer) + "Turn a rustc DIAGNOSTIC into a `flycheck-error'. + +CHECKER and BUFFER denote the CHECKER that returned DIAGNOSTIC +and the BUFFER that was checked respectively. + +DIAGNOSTIC should be a parsed JSON object describing a rustc +diagnostic, following the format described there: + +https://github.com/rust-lang/rust/blob/master/src/librustc_errors/json.rs#L154" + (let ((error-message) + (error-level) + (error-code) + (primary-filename) + (primary-line) + (primary-column) + (primary-end-line) + (primary-end-column) + (group (make-symbol "group")) + (spans) + (children) + (errors)) + ;; The diagnostic format is described in the link above. The gist of it is + ;; that a diagnostic can have several causes in the source text; these + ;; causes are represented by spans. The diagnostic has a message and a + ;; level (error, warning), while the spans have a filename, line, column, + ;; and an optional label. The primary span points to the root cause of the + ;; error in the source text, while non-primary spans point to related + ;; causes. Spans may have an 'expansion' field for macro expansion errors; + ;; these expansion fields will contain another span (and so on). In + ;; addition, a diagnostic can also have children diagnostics that are used + ;; to provide additional information through their message field, but do not + ;; seem to contain any spans (yet). + ;; + ;; We first gather spans in order to turn every span into a flycheck error + ;; object, that we collect into the `errors' list. + + ;; Nested `let-alist' cause compilation warnings, hence we `setq' all + ;; these values here first to avoid nesting. + (let-alist diagnostic + (setq error-message .message + error-level (pcase .level + (`"error" 'error) + (`"warning" 'warning) + (`"note" 'info) + (_ 'error)) + ;; The 'code' field of the diagnostic contains the actual error + ;; code and an optional explanation that we ignore + error-code .code.code + ;; Collect all spans recursively + spans (seq-mapcat #'flycheck-parse-rust-collect-spans .spans) + children .children)) + + ;; Turn each span into a flycheck error + (dolist (span spans) + (let-alist span + ;; Children may not have filename/line/column information, so we use + ;; those from the primary span + (when .is_primary + (setq primary-filename .file_name + primary-line .line_start + primary-column .column_start + primary-end-line .line_end + primary-end-column .column_end)) + (push + (flycheck-error-new-at + .line_start + .column_start + ;; Non-primary spans are used for notes + (if .is_primary error-level 'info) + (if .is_primary + ;; Primary spans may have labels with additional information + (concat error-message (when .label + (format " (%s)" .label))) + ;; If the label is empty, fallback on the error message, + ;; otherwise we won't be able to display anything + (or .label error-message)) + :id error-code + :checker checker + :buffer buffer + :filename .file_name + :group group + :end-line .line_end + :end-column .column_end) + errors))) + + ;; Then we turn children messages into flycheck errors pointing to the + ;; location of the primary span. + (dolist (child children) + (let ((message (let-alist child .message))) + (let-alist (car (let-alist child .spans)) + (push + (flycheck-error-new-at + ;; Use the line/column from the first span if there is one, or + ;; fallback to the line/column information from the primary span of + ;; the diagnostic. + (or .line_start primary-line) + (or .column_start primary-column) + 'info + ;; Messages from `cargo clippy' may suggest replacement code. In + ;; these cases, the `message' field itself is an unhelpful `try' or + ;; `change this to'. We add the `suggested_replacement' field in + ;; these cases. + (if .suggested_replacement + (format "%s: `%s`" message .suggested_replacement) + message) + :id error-code + :checker checker + :buffer buffer + :filename primary-filename + :group group + :end-line (or .line_end primary-end-line) + :end-column (or .column_end primary-end-column)) + errors)))) + + ;; If there are no spans, the error is not associated with a specific + ;; file but with the project as a whole. We still need to report it to + ;; the user by emitting a corresponding flycheck-error object. + (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))) + +(defconst flycheck--json-parser + (if (and (functionp 'json-parse-buffer) + ;; json-parse-buffer only supports keyword arguments in Emacs 27+ + (>= emacs-major-version 27)) + (lambda () + (json-parse-buffer + :object-type 'alist :array-type 'list + :null-object nil :false-object nil)) + #'json-read) + "Function to use to parse JSON strings.") + +(defun flycheck-parse-json (output) + "Return parsed JSON data from OUTPUT. + +OUTPUT is a string that contains JSON data. Each line of OUTPUT +may be either plain text, a JSON array (starting with `['), or a +JSON object (starting with `{'). + +This function ignores the plain text lines, parses the JSON +lines, and returns the parsed JSON lines in a list." + (let ((objects nil) + (json-array-type 'list) + (json-false nil)) + (with-temp-buffer + (insert output) + (goto-char (point-min)) + (while (not (eobp)) + (when (memq (char-after) '(?\{ ?\[)) + (push (funcall flycheck--json-parser) objects)) + (forward-line))) + (nreverse objects))) + +(defun flycheck-parse-rustc (output checker buffer) + "Parse rustc errors from OUTPUT and return a list of `flycheck-error'. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +The expected format for OUTPUT is a mix of plain text lines and +JSON lines. This function ignores the plain text lines and +parses only JSON lines. Each JSON line is expected to be a JSON +object that corresponds to a diagnostic from the compiler. The +expected diagnostic format is described there: + +https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs#L67-L139" + (seq-mapcat (lambda (msg) + (flycheck-parse-rustc-diagnostic msg checker buffer)) + (flycheck-parse-json output))) + +(defun flycheck-parse-cargo-rustc (output checker buffer) + "Parse Cargo errors from OUTPUT and return a list of `flycheck-error'. + +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +The expected format for OUTPUT is a mix of plain text lines and +JSON lines. This function ignores the plain text lines and +parses only JSON lines. Each JSON line is expected to be a JSON +object that represents a message from Cargo. The format of +messages emitted by Cargo is described in cargo's +machine_message.rs at URL `https://git.io/vh24R'." + (let ((errors)) + (dolist (msg (flycheck-parse-json output)) + (let-alist msg + ;; Errors and warnings from rustc are wrapped by cargo, so we filter and + ;; unwrap them, and delegate the actual construction of `flycheck-error' + ;; objects to `flycheck-parse-rustc-diagnostic'. + (when (string= .reason "compiler-message") + (push (flycheck-parse-rustc-diagnostic .message checker buffer) + errors)))) + (apply #'nconc errors))) + +;; Some checkers output ANSI terminal colors, which don't match up +;; with :error-patterns, so we strip those color codes from the output +;; here before passing it along to the default behavior. This is +;; originally only used in the rebar3 checker, but the systemd checker +;; now also makes use of it. +;; +;; The relevant discussion can be found at +;; https://github.com/flycheck/flycheck/pull/1144 +(defun flycheck-parse-with-patterns-without-color (output checker buffer) + "Strip color codes from OUTPUT before passing it to the default behavior. + +CHECKER and BUFFER are passed along as well." + (flycheck-parse-with-patterns + (and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output)) + checker buffer)) + + +;;; Error parsing with regular expressions +(defun flycheck-get-regexp (patterns) + "Create a single regular expression from PATTERNS." + (rx-to-string `(or ,@(seq-map (lambda (p) (list 'regexp (car p))) patterns)) + 'no-group)) + +(defun flycheck-tokenize-output-with-patterns (output patterns) + "Tokenize OUTPUT with PATTERNS. + +Split the output into error tokens, using all regular expressions +from the error PATTERNS. An error token is simply a string +containing a single error from OUTPUT. Such a token can then be +parsed into a structured error by applying the PATTERNS again, +see `flycheck-parse-errors-with-patterns'. + +Return a list of error tokens." + (let ((regexp (flycheck-get-regexp patterns)) + (last-match 0) + errors) + (while (string-match regexp output last-match) + (push (match-string 0 output) errors) + (setq last-match (match-end 0))) + (reverse errors))) + +(defun flycheck-try-parse-error-with-pattern (err pattern checker) + "Try to parse a single ERR with a PATTERN for CHECKER. + +Return the parsed error if PATTERN matched ERR, or nil +otherwise. + +`end-line' defaults to the value of `line' when `end-column' is +set, since checkers often omit redundant end lines (as in +::-)." + (let ((regexp (car pattern)) + (level (cdr pattern))) + (when (string-match regexp err) + (let ((filename (match-string 1 err)) + (line (flycheck-string-to-number-safe (match-string 2 err))) + (column (flycheck-string-to-number-safe (match-string 3 err))) + (message (match-string 4 err)) + (id (match-string 5 err)) + (end-line (flycheck-string-to-number-safe (match-string 6 err))) + (end-column (flycheck-string-to-number-safe (match-string 7 err)))) + (flycheck-error-new-at + line + column + level + (unless (string-empty-p message) message) + :id (unless (string-empty-p id) id) + :checker checker + :filename (if (or (null filename) (string-empty-p filename)) + (buffer-file-name) + filename) + :end-line (or end-line (and end-column line)) + :end-column end-column))))) + +(defun flycheck-parse-error-with-patterns (err patterns checker) + "Parse a single ERR with error PATTERNS for CHECKER. + +Apply each pattern in PATTERNS to ERR, in the given order, and +return the first parsed error." + ;; Try to parse patterns in the order of declaration to make sure that the + ;; first match wins. + (let (parsed-error) + (while (and patterns + (not (setq parsed-error + (flycheck-try-parse-error-with-pattern + err (car patterns) checker)))) + (setq patterns (cdr patterns))) + parsed-error)) + +(defun flycheck-parse-with-patterns (output checker buffer) + "Parse OUTPUT from CHECKER with error patterns. + +Uses the error patterns of CHECKER to tokenize the output and +tries to parse each error token with all patterns, in the order +of declaration. Hence an error is never matched twice by two +different patterns. The pattern declared first always wins. + +_BUFFER is ignored. + +Return a list of parsed errors and warnings (as `flycheck-error' +objects)." + (with-current-buffer buffer + (let ((patterns (flycheck-checker-get checker 'error-patterns))) + (seq-map (lambda (err) + (flycheck-parse-error-with-patterns err patterns checker)) + (flycheck-tokenize-output-with-patterns output patterns))))) + + +;;; Convenience definition of command-syntax checkers + +;; This macro is autoloaded to prevent `with-eval-after-load' from expanding its +;; arguments. See https://github.com/flycheck/flycheck/issues/1398. +;;;###autoload +(defmacro flycheck-define-checker (symbol docstring &rest properties) + "Define SYMBOL as command syntax checker with DOCSTRING and PROPERTIES. + +Like `flycheck-define-command-checker', but PROPERTIES must not +be quoted. Also, implicitly define the executable variable for +SYMBOL with `flycheck-def-executable-var'." + (declare (indent 1) + (doc-string 2)) + (let ((command (plist-get properties :command)) + (parser (plist-get properties :error-parser)) + (filter (plist-get properties :error-filter)) + (explainer (plist-get properties :error-explainer)) + (predicate (plist-get properties :predicate)) + (enabled-fn (plist-get properties :enabled)) + (verify-fn (plist-get properties :verify))) + + `(progn + (flycheck-def-executable-var ,symbol ,(car command)) + + (flycheck-define-command-checker ',symbol + ,docstring + :command ',command + ,@(when parser + `(:error-parser #',parser)) + :error-patterns ',(plist-get properties :error-patterns) + ,@(when filter + `(:error-filter #',filter)) + ,@(when explainer + `(:error-explainer #',explainer)) + :modes ',(plist-get properties :modes) + ,@(when predicate + `(:predicate #',predicate)) + :next-checkers ',(plist-get properties :next-checkers) + ,@(when enabled-fn + `(:enabled #',enabled-fn)) + ,@(when verify-fn + `(:verify #',verify-fn)) + :standard-input ',(plist-get properties :standard-input) + :working-directory ',(plist-get properties :working-directory))))) + + +;;; Built-in checkers +(flycheck-def-args-var flycheck-gnat-args ada-gnat + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gnat-include-path nil ada-gnat + "A list of include directories for GNAT. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of gcc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gnat-language-standard "2012" ada-gnat + "The language standard to use in GNAT. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, pass +the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gnat-warnings + '("wa") ada-gnat + "A list of additional Ada warnings to enable in GNAT. + +The value of this variable is a list of strings, where each +string is the name of a warning category to enable. By default, +most optional warnings are recommended, as in `-gnata'. + +Refer to Info Node `(gnat_ugn_unw)Warning Message Control' for +more information about GNAT warnings." + :type '(repeat :tag "Warnings" (string :tag "Warning name")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker ada-gnat + "An Ada syntax checker using GNAT. + +Uses the GNAT compiler from GCC. See URL +`https://www.adacore.com/community/'." + :command ("gnatmake" + "-c" ; Just compile, don't bind + "-f" ; Force re-compilation + "-u" ; Compile the main file only + "-gnatf" ; Full error information + "-gnatef" ; Full source file name + "-D" temporary-directory + (option-list "-gnat" flycheck-gnat-warnings concat) + (option-list "-I" flycheck-gnat-include-path concat) + (option "-gnat" flycheck-gnat-language-standard concat) + (eval flycheck-gnat-args) + source) + :error-patterns + ((error line-start + (message "In file included from") " " (file-name) ":" line ":" + column ":" + line-end) + (info line-start (file-name) ":" line ":" column + ": note: " (message) line-end) + (warning line-start (file-name) ":" line ":" column + ": warning: " (message) line-end) + ;; no specific error prefix in Ada + (error line-start (file-name) ":" line ":" column + ": " (message) line-end)) + :modes ada-mode) + +(flycheck-define-checker asciidoc + "A AsciiDoc syntax checker using the AsciiDoc compiler. + +See URL `http://www.methods.co.nz/asciidoc'." + :command ("asciidoc" "-o" null-device "-") + :standard-input t + :error-patterns + ((error line-start + "asciidoc: ERROR: : Line " line ": " (message) + line-end) + (warning line-start + "asciidoc: WARNING: : Line " line ": " (message) + line-end) + (info line-start + "asciidoc: DEPRECATED: : Line " line ": " (message) + line-end)) + :modes adoc-mode) + +(flycheck-define-checker asciidoctor + "An AsciiDoc syntax checker using the Asciidoctor compiler. + +See URL `http://asciidoctor.org'." + :command ("asciidoctor" "-o" null-device "-") + :standard-input t + :error-patterns + ((error line-start + "asciidoctor: ERROR: : Line " line ": " (message) + line-end) + (warning line-start + "asciidoctor: WARNING: : Line " line ": " (message) + line-end)) + :modes adoc-mode) + +(defun flycheck-awk-gawk-fix-message (err) + "Remove the repeated file-name/line from the error message of ERR." + (setf (flycheck-error-message err) + (replace-regexp-in-string + (rx line-start + (group (zero-or-more (any " " "\t"))) + (group (zero-or-more nonl) "\n") + (backref 1)) + "\\2" + (replace-regexp-in-string + (rx "\ngawk: " (zero-or-more (not (any " "))) ":") + "\n" + (flycheck-error-message err)))) + err) + +(defun flycheck-awk-gawk-error-filter (errors) + "Remove repeated file-name/line from ERRORS." + (seq-do #'flycheck-awk-gawk-fix-message errors) + errors) + +(flycheck-define-checker awk-gawk + "GNU awk's built-in --lint checker." + :command ("gawk" + ;; Avoid code execution. See https://github.com/w0rp/ale/pull/1411 + "--source" "'BEGIN{exit} END{exit 1}'" + "-f" source + "--lint" + "/dev/null") + :standard-input nil + :error-patterns + ((warning line-start + "gawk: " + (file-name) ":" line ":" (optional column ":") + (message (one-or-more not-newline) + (optional "\n" + (one-or-more not-newline) + " ^ " + (one-or-more not-newline))) + line-end)) + :error-filter flycheck-awk-gawk-error-filter + :modes awk-mode) + +(flycheck-define-checker bazel-buildifier + "An Bazel checker using the buildifier. + +See URL `https://github.com/bazelbuild/buildtools/blob/master/buildifier'." + :command ("buildifier" "-lint=warn") + :standard-input t + :error-patterns + ((error line-start + ":" line ":" column ": " (message) + line-end) + (warning line-start + ":" line ": " (id (one-or-more (in word "-"))) ": " (message) + line-end)) + :modes bazel-mode) + +(flycheck-def-args-var flycheck-clang-args c/c++-clang + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-clang-blocks nil c/c++-clang + "Enable blocks in Clang. + +When non-nil, enable blocks in Clang with `-fblocks'. See URL +`http://clang.llvm.org/docs/BlockLanguageSpec.html' for more +information about blocks." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-clang-definitions nil c/c++-clang + "Additional preprocessor definitions for Clang. + +The value of this variable is a list of strings, where each +string is an additional definition to pass to Clang, via the `-D' +option." + :type '(repeat (string :tag "Definition")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-include-path nil c/c++-clang + "A list of include directories for Clang. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of Clang. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.14")) + +(flycheck-def-option-var flycheck-clang-includes nil c/c++-clang + "A list of additional include files for Clang. + +The value of this variable is a list of strings, where each +string is a file to include before syntax checking. Relative +paths are relative to the file being checked." + :type '(repeat (file :tag "Include file")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-language-standard nil c/c++-clang + "The language standard to use in Clang. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.15")) +(make-variable-buffer-local 'flycheck-clang-language-standard) + +(flycheck-def-option-var flycheck-clang-ms-extensions nil c/c++-clang + "Whether to enable Microsoft extensions to C/C++ in Clang. + +When non-nil, enable Microsoft extensions to C/C++ via +`-fms-extensions'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-clang-no-exceptions nil c/c++-clang + "Whether to disable exceptions in Clang. + +When non-nil, disable exceptions for syntax checks, via +`-fno-exceptions'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-clang-no-rtti nil c/c++-clang + "Whether to disable RTTI in Clang. + +When non-nil, disable RTTI for syntax checks, via `-fno-rtti'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-pedantic nil c/c++-clang + "Whether to warn about language extensions in Clang. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-clang-pedantic-errors nil c/c++-clang + "Whether to error on language extensions in Clang. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic-errors'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-clang-standard-library nil c/c++-clang + "The standard library to use for Clang. + +The value of this variable is the name of a standard library as +string, or nil to use the default standard library. + +Refer to the Clang manual at URL +`http://clang.llvm.org/docs/UsersManual.html' for more +information about the standard library." + :type '(choice (const :tag "Default standard library" nil) + (const "libc++") + (const :tag "GNU libstdc++" "libstdc++") + (string :tag "Library name")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.15")) + +(flycheck-def-option-var flycheck-clang-warnings '("all" "extra") c/c++-clang + "A list of additional warnings to enable in Clang. + +The value of this variable is a list of strings, where each string +is the name of a warning category to enable. By default, all +recommended warnings and some extra warnings are enabled (as by +`-Wall' and `-Wextra' respectively). + +Refer to the Clang manual at URL +`http://clang.llvm.org/docs/UsersManual.html' for more +information about warnings." + :type '(choice (const :tag "No additional warnings" nil) + (repeat :tag "Additional warnings" + (string :tag "Warning name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.14")) + +(defun flycheck-c/c++-quoted-include-directory () + "Get the directory for quoted includes. + +C/C++ 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 #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.20")) +(make-variable-buffer-local 'flycheck-gcc-language-standard) + +(flycheck-def-option-var flycheck-gcc-no-exceptions nil c/c++-gcc + "Whether to disable exceptions in GCC. + +When non-nil, disable exceptions for syntax checks, via +`-fno-exceptions'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-no-rtti nil c/c++-gcc + "Whether to disable RTTI in GCC. + +When non-nil, disable RTTI for syntax checks, via `-fno-rtti'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gcc-openmp nil c/c++-gcc + "Whether to enable OpenMP in GCC. + +When non-nil, enable OpenMP for syntax checkers, via +`-fopenmp'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.21")) + +(flycheck-def-option-var flycheck-gcc-pedantic nil c/c++-gcc + "Whether to warn about language extensions in GCC. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-gcc-pedantic-errors nil c/c++-gcc + "Whether to error on language extensions in GCC. + +For ISO C, follows the version specified by any -std option used. +When non-nil, disable non-ISO extensions to C/C++ via +`-pedantic-errors'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-gcc-warnings '("all" "extra") c/c++-gcc + "A list of additional warnings to enable in GCC. + +The value of this variable is a list of strings, where each string +is the name of a warning category to enable. By default, all +recommended warnings and some extra warnings are enabled (as by +`-Wall' and `-Wextra' respectively). + +Refer to the gcc manual at URL +`https://gcc.gnu.org/onlinedocs/gcc/' for more information about +warnings." + :type '(choice (const :tag "No additional warnings" nil) + (repeat :tag "Additional warnings" + (string :tag "Warning name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker c/c++-gcc + "A C/C++ syntax checker using GCC. + +Requires GCC 4.4 or newer. See URL `https://gcc.gnu.org/'." + :command ("gcc" + "-fshow-column" + "-iquote" (eval (flycheck-c/c++-quoted-include-directory)) + (option "-std=" flycheck-gcc-language-standard concat) + (option-flag "-pedantic" flycheck-gcc-pedantic) + (option-flag "-pedantic-errors" flycheck-gcc-pedantic-errors) + (option-flag "-fno-exceptions" flycheck-gcc-no-exceptions) + (option-flag "-fno-rtti" flycheck-gcc-no-rtti) + (option-flag "-fopenmp" flycheck-gcc-openmp) + (option-list "-include" flycheck-gcc-includes) + (option-list "-W" flycheck-gcc-warnings concat) + (option-list "-D" flycheck-gcc-definitions concat) + (option-list "-I" flycheck-gcc-include-path) + (eval flycheck-gcc-args) + "-x" (eval + (pcase major-mode + (`c++-mode "c++") + (`c-mode "c"))) + ;; GCC performs full checking only when actually compiling, so + ;; `-fsyntax-only' is not enough. Just let it generate assembly + ;; code. + "-S" "-o" null-device + ;; Read from standard input + "-") + :standard-input t + :error-patterns + ((info line-start (or "" (file-name)) ":" line ":" 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 #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-cppcheck-suppressions-file) + +(flycheck-def-option-var flycheck-cppcheck-suppressions nil c/c++-cppcheck + "The suppressions to use in cppcheck. + +The value of this variable is either a list of strings denoting +the suppressions to use, or nil to pass nothing to cppcheck. +When non-nil, pass the suppressions via one or more `--suppress=' +options." + :type '(choice (const :tag "Default" nil) + (repeat :tag "Additional suppressions" + (string :tag "Suppression"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "28")) + +(flycheck-def-option-var flycheck-cppcheck-inconclusive nil c/c++-cppcheck + "Whether to enable Cppcheck inconclusive checks. + +When non-nil, enable Cppcheck inconclusive checks. This allows Cppcheck to +report warnings it's not certain of, but it may result in false positives. + +This will have no effect when using Cppcheck 1.53 and older." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.19")) + +(flycheck-def-option-var flycheck-cppcheck-include-path nil c/c++-cppcheck + "A list of include directories for cppcheck. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of cppcheck. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker c/c++-cppcheck + "A C/C++ checker using cppcheck. + +See URL `http://cppcheck.sourceforge.net/'." + :command ("cppcheck" "--quiet" "--xml-version=2" "--inline-suppr" + (option "--enable=" flycheck-cppcheck-checks concat + flycheck-option-comma-separated-list) + (option-flag "--inconclusive" flycheck-cppcheck-inconclusive) + (option-list "-I" flycheck-cppcheck-include-path) + (option-list "--std=" flycheck-cppcheck-standards concat) + (option-list "--suppress=" flycheck-cppcheck-suppressions concat) + (option "--suppressions-list=" + flycheck-cppcheck-suppressions-file concat) + "-x" (eval + (pcase major-mode + (`c++-mode "c++") + (`c-mode "c"))) + source) + :error-parser flycheck-parse-cppcheck + :modes (c-mode c++-mode)) + +(flycheck-define-checker cfengine + "A CFEngine syntax checker using cf-promises. + +See URL `https://cfengine.com/'." + :command ("cf-promises" "-Wall" "-f" + ;; We must stay in the same directory to resolve @include + source-inplace) + :error-patterns + ((warning line-start (file-name) ":" line ":" column + ": warning: " (message) line-end) + (error line-start (file-name) ":" line ":" column + ": error: " (message) line-end)) + :modes (cfengine-mode cfengine3-mode)) + +(flycheck-def-option-var flycheck-foodcritic-tags nil chef-foodcritic + "A list of tags to select for Foodcritic. + +The value of this variable is a list of strings where each string +is a tag expression describing Foodcritic rules to enable or +disable, via the `--tags' option. To disable a tag, prefix it +with `~'." + :type '(repeat :tag "Tags" (string :tag "Tag expression")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.23")) + +(flycheck-define-checker chef-foodcritic + "A Chef cookbooks syntax checker using Foodcritic. + +See URL `http://www.foodcritic.io'." + ;; Use `source-inplace' to allow resource discovery with relative paths. + ;; foodcritic interprets these as relative to the source file, so we need to + ;; stay within the source tree. See + ;; https://github.com/flycheck/flycheck/pull/556 + :command ("foodcritic" + (option-list "--tags" flycheck-foodcritic-tags) + source-inplace) + :error-patterns + ((error line-start (id (one-or-more alnum)) ": " + (message) ": " (file-name) ":" line line-end)) + :modes (enh-ruby-mode ruby-mode) + :predicate + (lambda () + (let ((parent-dir (file-name-directory + (directory-file-name + (expand-file-name default-directory))))) + (or + ;; Chef CookBook + ;; http://docs.opscode.com/chef/knife.html#id38 + (locate-dominating-file parent-dir "recipes") + ;; Knife Solo + ;; http://matschaffer.github.io/knife-solo/#label-Init+command + (locate-dominating-file parent-dir "cookbooks"))))) + +(flycheck-define-checker coffee + "A CoffeeScript syntax checker using coffee. + +See URL `https://coffeescript.org/'." + ;; --print suppresses generation of compiled .js files + :command ("coffee" "--compile" "--print" "--stdio") + :standard-input t + :error-patterns + ((error line-start "[stdin]:" line ":" column + ": error: " (message) line-end)) + :modes coffee-mode + :next-checkers ((warning . coffee-coffeelint))) + +(flycheck-def-config-file-var flycheck-coffeelintrc coffee-coffeelint + ".coffeelint.json") + +(flycheck-define-checker coffee-coffeelint + "A CoffeeScript style checker using coffeelint. + +See URL `http://www.coffeelint.org/'." + :command + ("coffeelint" + (config-file "--file" flycheck-coffeelintrc) + "--stdin" "--reporter" "checkstyle") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter (lambda (errors) + (flycheck-remove-error-file-names + "stdin" (flycheck-remove-error-ids + (flycheck-sanitize-errors errors)))) + :modes coffee-mode) + +(defun flycheck-coq-error-filter (errors) + "Sanitize Coq ERRORS and compute end-lines and end-columns." + (flycheck-increment-error-columns errors) + (dolist (err errors) + (setf (flycheck-error-message err) + (replace-regexp-in-string (rx (1+ (syntax whitespace)) line-end) + "" (flycheck-error-message err) + 'fixedcase 'literal)) + (-when-let* ((end-col (flycheck-error-end-column err))) + ;; Coq reports an offset (potentially past eol), not an end column + (let* ((line (flycheck-error-line err)) + (end-lc (save-excursion + (flycheck-goto-line line) + (goto-char (+ (point) (1- end-col))) + (flycheck-line-column-at-point)))) + (setf (flycheck-error-end-line err) (car end-lc)) + (setf (flycheck-error-end-column err) (cdr end-lc))))) + (flycheck-sanitize-errors errors)) + +(flycheck-define-checker coq + "A Coq syntax checker using the Coq compiler. + +See URL `https://coq.inria.fr/'." + ;; We use coqtop in batch mode, because coqc is picky about file names. + :command ("coqtop" "-batch" "-load-vernac-source" source) + :error-patterns + ((error line-start "File \"" (file-name) "\", line " line + ", characters " column "-" end-column ":\n" + (or "Syntax error:" "Error:") + ;; Most Coq error messages span multiple lines, and end with a dot. + ;; There are simple one-line messages, too, though. + (message (or (and (one-or-more (or not-newline "\n")) ".") + (one-or-more not-newline))) + line-end)) + :error-filter flycheck-coq-error-filter + :modes coq-mode) + +(flycheck-define-checker css-csslint + "A CSS syntax and style checker using csslint. + +See URL `https://github.com/CSSLint/csslint'." + :command ("csslint" "--format=checkstyle-xml" source) + :error-parser flycheck-parse-checkstyle + :error-filter flycheck-dequalify-error-ids + :modes css-mode) + +(defconst flycheck-stylelint-args '("--formatter" "json") + "Common arguments to stylelint invocations.") + +(flycheck-def-config-file-var flycheck-stylelintrc + (css-stylelint scss-stylelint less-stylelint) nil) + +(flycheck-def-option-var flycheck-stylelint-quiet + nil (css-stylelint scss-stylelint less-stylelint) + "Whether to run stylelint in quiet mode. + +When non-nil, enable quiet mode, via `--quiet'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . 26)) + +(defconst flycheck-stylelint-error-re + (flycheck-rx-to-string + '(: line-start (id (one-or-more word)) ": " (message) line-end))) + +(defun flycheck-parse-stylelint (output checker buffer) + "Parse stylelint errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +The CHECKER usually returns the errors as JSON. + +If the CHECKER throws an Error it returns an Error message with a stacktrace." + (condition-case nil + (flycheck-parse-stylelint-json output checker buffer) + + ;; The output could not be parsed as JSON + (json-error + + ;; Extract a flycheck error from the output (with a regular expression) + ;; For match-string 4/5 see flycheck-rx-message/flycheck-rx-id + (when (string-match flycheck-stylelint-error-re output) + (list (flycheck-error-new-at + 1 nil 'error + (match-string 4 output) + :id (match-string 5 output) + :checker checker + :buffer buffer + :filename (buffer-file-name buffer))))))) + +(defun flycheck-parse-stylelint-json (output checker buffer) + "Parse stylelint JSON errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://stylelint.io/developer-guide/formatters/' for information +about the JSON format of stylelint." + (let ((json-object-type 'plist)) + + ;; stylelint returns a vector of result objects + ;; Since we only passed one file, the first element is enough + (let* ((stylelint-output (elt (json-read-from-string output) 0)) + (filename (buffer-file-name buffer)) + + ;; Turn all deprecations into warnings + (deprecations + (mapcar (lambda (d) + (flycheck-error-new-at + 1 nil 'warning + (plist-get d :text) + :id "Deprecation Warning" + :checker checker + :buffer buffer + :filename filename)) + (plist-get stylelint-output :deprecations))) + + ;; Turn all invalid options into errors + (invalid-options + (mapcar (lambda (io) + (flycheck-error-new-at + 1 nil 'error + (plist-get io :text) + :id "Invalid Option" + :checker checker + :buffer buffer + :filename filename)) + (plist-get stylelint-output :invalidOptionWarnings))) + + ;; Read all linting warnings + (warnings + (mapcar (lambda (w) + (flycheck-error-new-at + (plist-get w :line) (plist-get w :column) + (pcase (plist-get w :severity) + (`"error" 'error) + (`"warning" 'warning) + ;; Default to info for unknown .severity + (_ 'info)) + (plist-get w :text) + :id (plist-get w :rule) + :checker checker + :buffer buffer + :filename filename)) + (plist-get stylelint-output :warnings)))) + + ;; Return the combined errors (deprecations, invalid options, warnings) + (append deprecations invalid-options warnings)))) + +(flycheck-define-checker css-stylelint + "A CSS syntax and style checker using stylelint. + +See URL `http://stylelint.io/'." + :command ("stylelint" + (eval flycheck-stylelint-args) + (option-flag "--quiet" flycheck-stylelint-quiet) + (config-file "--config" flycheck-stylelintrc) + "--stdin-filename" (eval (or (buffer-file-name) "style.css"))) + :standard-input t + :error-parser flycheck-parse-stylelint + :predicate flycheck-buffer-nonempty-p + :modes (css-mode)) + +(flycheck-def-option-var flycheck-cuda-language-standard nil cuda-nvcc + "Our CUDA Language Standard." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-cuda-language-standard) + +(flycheck-def-option-var flycheck-cuda-includes nil cuda-nvcc + "Our include directories to pass to nvcc." + :type '(repeat (file :tag "Include file")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-cuda-definitions nil cuda-nvcc + "Additional preprocessor definitions for nvcc. +A list of strings to pass to cuda, a la flycheck-clang" + :type '(repeat (string :tag "Definitions")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-cuda-include-path nil cuda-nvcc + "A list of include directories for nvcc." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker cuda-nvcc + "A CUDA C/C++ syntax checker using nvcc. + +See URL `https://developer.nvidia.com/cuda-llvm-compiler'." + :command ("nvcc" + "-c" ;; Compile Only + "--output-file" "/dev/null" ;; avoid creating output .o + "--x=cu" ;; explicitly specify it's a CUDA language file + (option "-std=" flycheck-cuda-language-standard concat) + (option-list "-include" flycheck-cuda-includes) + (option-list "-D" flycheck-cuda-definitions concat) + (option-list "-I" flycheck-cuda-include-path) + source) + :error-patterns + ((error line-start + (message "In file included from") + " " (or "" (file-name)) + ":" line ":" line-end) + (error line-start (or "" (file-name)) + "(" line "): error: " (message) line-end) + (error line-start (or "" (file-name)) + ":" line ":" column + ": fatal error: " (optional (message)) line-end) + (warning line-start (or "" (file-name)) + "(" line "): warning: " (message) line-end)) + :modes cuda-mode) + + +(flycheck-def-option-var flycheck-cwl-schema-path nil cwl + "A path for the schema file for Common Workflow Language. + +The value of this variable is a string that denotes a path for +the schema file of Common Workflow Language." + :type '(choice (const :tag "None" nil) + (file :tag "Schema file")) + :safe #'flycheck-string-or-nil-p) + +(flycheck-define-checker cwl + "A CWL syntax checker using Schema Salad validator. + +Requires Schema Salad 2.6.20171101113912 or newer. +See URL `https://www.commonwl.org/v1.0/SchemaSalad.html'." + :command ("schema-salad-tool" + "--quiet" + "--print-oneline" + (eval flycheck-cwl-schema-path) + source-inplace) + :error-patterns + ((error line-start + (file-name) ":" line ":" column ":" (zero-or-more blank) + (message (one-or-more not-newline)) + line-end)) + :modes cwl-mode) + +(defconst flycheck-d-module-re + (rx "module" (one-or-more (syntax whitespace)) + (group (one-or-more (not (syntax whitespace)))) + (zero-or-more (syntax whitespace)) + ";") + "Regular expression to match a D module declaration.") + +(defun flycheck-d-base-directory () + "Get the relative base directory path for this module." + (let* ((file-name (buffer-file-name)) + (module-file (if (and file-name + (string= (file-name-nondirectory file-name) + "package.d")) + (directory-file-name (file-name-directory file-name)) + file-name))) + (flycheck-module-root-directory + (flycheck-find-in-buffer flycheck-d-module-re) + module-file))) + +(flycheck-def-option-var flycheck-dmd-include-path nil d-dmd + "A list of include directories for dmd. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of dmd. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.18")) + +(flycheck-def-args-var flycheck-dmd-args d-dmd + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker d-dmd + "A D syntax checker using the DMD compiler. + +Requires DMD 2.066 or newer. See URL `https://dlang.org/'." + :command ("dmd" + "-debug" ; Compile in debug mode + "-o-" ; Don't generate an object file + "-vcolumns" ; Add columns in output + "-wi" ; Compilation will continue even if there are warnings + (eval (concat "-I" (flycheck-d-base-directory))) + (option-list "-I" flycheck-dmd-include-path concat) + (eval flycheck-dmd-args) + (source ".d")) + :error-patterns + ((error line-start + (file-name) "(" line "," column "): Error: " (message) + line-end) + (warning line-start (file-name) "(" line "," column "): " + (or "Warning" "Deprecation") ": " (message) line-end) + (info line-start (file-name) "(" line "," column "): " + (one-or-more " ") (message) line-end)) + :modes d-mode) + +(flycheck-define-checker dockerfile-hadolint + "A Dockerfile syntax checker using the hadolint. + +See URL `http://github.com/hadolint/hadolint/'." + :command ("hadolint" "-") + :standard-input t + :error-patterns + ((error line-start + (file-name) ":" line ":" column " " (message) + line-end) + (warning line-start + (file-name) ":" line " " (id (one-or-more alnum)) " " (message) + line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "/dev/stdin" errors))) + :modes dockerfile-mode) + +(defun flycheck-credo--working-directory (&rest _ignored) + "Check if `credo' is installed as dependency in the application." + (and buffer-file-name + (locate-dominating-file buffer-file-name "deps/credo"))) + +(flycheck-def-option-var flycheck-elixir-credo-strict nil elixir-credo + "Enable strict mode in `credo'. + +When non-nil, pass the `--strict' flag to credo." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "32")) + +(flycheck-define-checker elixir-credo + "An Elixir checker for static code analysis using Credo. + +See `http://credo-ci.org/'." + :command ("mix" "credo" + (option-flag "--strict" flycheck-elixir-credo-strict) + "--format" "flycheck" + "--read-from-stdin" source-original) + :standard-input t + :working-directory flycheck-credo--working-directory + :enabled flycheck-credo--working-directory + :error-patterns + ((info line-start + (file-name) ":" line (optional ":" column) ": " + (or "F" "R" "C") ": " (message) line-end) + (warning line-start + (file-name) ":" line (optional ":" column) ": " + (or "D" "W") ": " (message) line-end)) + :modes elixir-mode) + +(defconst flycheck-this-emacs-executable + (concat invocation-directory invocation-name) + "The path to the currently running Emacs executable.") + +(defconst flycheck-emacs-args '("-Q" "--batch") + "Common arguments to Emacs invocations.") + +(defmacro flycheck-prepare-emacs-lisp-form (&rest body) + "Prepare BODY for use as check form in a subprocess." + (declare (indent 0)) + `(flycheck-sexp-to-string + '(progn + (defvar jka-compr-inhibit) + (unwind-protect + ;; Flycheck inhibits compression of temporary files, thus we + ;; must not attempt to decompress. + (let ((jka-compr-inhibit t)) + ;; Strip option-argument separator from arguments, if present + (when (equal (car command-line-args-left) "--") + (setq command-line-args-left (cdr command-line-args-left))) + ,@body) + ;; Prevent Emacs from processing the arguments on its own, see + ;; https://github.com/flycheck/flycheck/issues/319 + (setq command-line-args-left nil))))) + +(defun flycheck-emacs-lisp-bytecomp-config-form () + "Prepare an Emacs Lisp form to set byte-compiler variables." + (flycheck-sexp-to-string + `(progn + (require 'bytecomp) + (setq byte-compile-root-dir + ,(if buffer-file-name + (file-name-directory buffer-file-name) + default-directory))))) + +(defconst flycheck-emacs-lisp-check-form + (flycheck-prepare-emacs-lisp-form + ;; Keep track of the generated bytecode files, to delete them after byte + ;; compilation. + (require 'bytecomp) + (defvar flycheck-byte-compiled-files nil) + (let ((byte-compile-dest-file-function + (lambda (source) + (let ((temp-file (make-temp-file (file-name-nondirectory source)))) + (push temp-file flycheck-byte-compiled-files) + temp-file)))) + (unwind-protect + (byte-compile-file (car command-line-args-left)) + (mapc (lambda (f) (ignore-errors (delete-file f))) + flycheck-byte-compiled-files)) + (when (bound-and-true-p flycheck-emacs-lisp-check-declare) + (check-declare-file (car command-line-args-left)))))) + +(flycheck-def-option-var flycheck-emacs-lisp-load-path nil emacs-lisp + "Load path to use in the Emacs Lisp syntax checker. + +When set to `inherit', use the `load-path' of the current Emacs +session during syntax checking. + +When set to a list of strings, add each directory in this list to +the `load-path' before invoking the byte compiler. Relative +paths in this list are expanded against the `default-directory' +of the buffer to check. + +When nil, do not explicitly set the `load-path' during syntax +checking. The syntax check only uses the built-in `load-path' of +Emacs in this case. + +Note that changing this variable can lead to wrong results of the +syntax check, e.g. if an unexpected version of a required library +is used." + :type '(choice (const :tag "Inherit current `load-path'" inherit) + (repeat :tag "Load path" directory)) + :risky t + :package-version '(flycheck . "0.14")) + +(flycheck-def-option-var flycheck-emacs-lisp-initialize-packages + 'auto emacs-lisp + "Whether to initialize packages in the Emacs Lisp syntax checker. + +When nil, never initialize packages. When `auto', initialize +packages only when checking `user-init-file' or files from +`user-emacs-directory'. For any other non-nil value, always +initialize packages. + +When initializing packages is enabled the `emacs-lisp' syntax +checker calls `package-initialize' before byte-compiling the file +to be checked. It also sets `package-user-dir' according to +`flycheck-emacs-lisp-package-user-dir'." + :type '(choice (const :tag "Do not initialize packages" nil) + (const :tag "Initialize packages for configuration only" auto) + (const :tag "Always initialize packages" t)) + :risky t + :package-version '(flycheck . "0.14")) + +(defconst flycheck-emacs-lisp-package-initialize-form + (flycheck-sexp-to-string + '(with-demoted-errors "Error during package initialization: %S" + (package-initialize))) + "Form used to initialize packages.") + +(defun flycheck-option-emacs-lisp-package-initialize (value) + "Option VALUE filter for `flycheck-emacs-lisp-initialize-packages'." + (let ((shall-initialize + (if (eq value 'auto) + (or (flycheck-in-user-emacs-directory-p + (or buffer-file-name default-directory)) + ;; `user-init-file' is nil in non-interactive sessions. Now, + ;; no user would possibly use Flycheck in a non-interactive + ;; session, but our unit tests run non-interactively, so we + ;; have to handle this case anyway + (and user-init-file buffer-file-name + (flycheck-same-files-p buffer-file-name user-init-file))) + value))) + (when shall-initialize + ;; If packages shall be initialized, return the corresponding form, + ;; otherwise make Flycheck ignore the option by returning nil. + flycheck-emacs-lisp-package-initialize-form))) + +(flycheck-def-option-var flycheck-emacs-lisp-package-user-dir nil emacs-lisp + "Package directory for the Emacs Lisp syntax checker. + +If set to a string set `package-user-dir' to the value of this +variable before initializing packages. If set to nil just inherit +the value of `package-user-dir' from the running Emacs session. + +This variable has no effect, if +`flycheck-emacs-lisp-initialize-packages' is nil." + :type '(choice (const :tag "Default package directory" nil) + (directory :tag "Custom package directory")) + :risky t + :package-version '(flycheck . "0.14")) + +(defun flycheck-option-emacs-lisp-package-user-dir (value) + "Option VALUE filter for `flycheck-emacs-lisp-package-user-dir'." + ;; Inherit the package directory from our Emacs session + (let ((value (or value (bound-and-true-p package-user-dir)))) + (when value + (flycheck-sexp-to-string `(setq package-user-dir ,value))))) + +(flycheck-def-option-var flycheck-emacs-lisp-check-declare nil emacs-lisp + "If non-nil, check ‘declare-function’ forms using ‘check-declare-file’." + :type '(choice (const :tag "Do not check declare forms" nil) + (const :tag "Check declare forms" t)) + :risky t + :package-version '(flycheck . "31")) + +(defun flycheck-option-emacs-lisp-check-declare (value) + "Option VALUE filter for `flycheck-emacs-lisp-check-declare'." + (when value + (flycheck-sexp-to-string + `(progn + (defvar flycheck-emacs-lisp-check-declare) + (setq flycheck-emacs-lisp-check-declare ,value))))) + +(defun flycheck--emacs-lisp-enabled-p () + "Check whether to enable Emacs Lisp checkers in the current buffer." + (not + (or + ;; Do not check buffers used for autoloads generation during package + ;; installation. These buffers are too short-lived for being checked, and + ;; doing so causes spurious errors. See + ;; https://github.com/flycheck/flycheck/issues/45 and + ;; https://github.com/bbatsov/prelude/issues/248. We must also not check + ;; compilation buffers, but as these are ephemeral, Flycheck won't check + ;; them anyway. + (flycheck-autoloads-file-p) + ;; Cask/Carton and dir-locals files contain data, not code, and don't need + ;; to follow Checkdoc conventions either. + (and (buffer-file-name) + (member (file-name-nondirectory (buffer-file-name)) + '("Cask" "Carton" ".dir-locals.el" ".dir-locals-2.el")))))) + +(flycheck-define-checker emacs-lisp + "An Emacs Lisp syntax checker using the Emacs Lisp Byte compiler. + +See Info Node `(elisp)Byte Compilation'." + :command ("emacs" (eval flycheck-emacs-args) + (eval + (let ((path (pcase flycheck-emacs-lisp-load-path + (`inherit load-path) + (p (seq-map #'expand-file-name p))))) + (flycheck-prepend-with-option "--directory" path))) + (option "--eval" flycheck-emacs-lisp-package-user-dir nil + flycheck-option-emacs-lisp-package-user-dir) + (option "--eval" flycheck-emacs-lisp-initialize-packages nil + flycheck-option-emacs-lisp-package-initialize) + (option "--eval" flycheck-emacs-lisp-check-declare nil + flycheck-option-emacs-lisp-check-declare) + "--eval" (eval (flycheck-emacs-lisp-bytecomp-config-form)) + "--eval" (eval flycheck-emacs-lisp-check-form) + "--" + source-inplace) + :error-patterns + ((error line-start (file-name) ":" line ":" column ":" + (zero-or-more whitespace) "Error:" (zero-or-more whitespace) + (message (zero-or-more not-newline) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + (warning line-start (file-name) ":" line ":" column ":" + (zero-or-more whitespace) "Warning:" (zero-or-more whitespace) + (message (zero-or-more not-newline) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + (warning line-start (file-name) ":" line (optional ":" column) ":" + (zero-or-more whitespace) "Warning (check-declare): said\n" + (message (zero-or-more " " (zero-or-more not-newline)) + (zero-or-more "\n " (zero-or-more not-newline))) + line-end) + ;; The following is for Emacs 24 ‘check-declare-file’, which uses a + ;; less informative format. + (warning line-start "Warning (check-declare): " (file-name) " said " + (message (zero-or-more not-newline)) + line-end)) + :error-filter + (lambda (errors) + (flycheck-fill-empty-line-numbers + (flycheck-collapse-error-message-whitespace + (flycheck-sanitize-errors errors)))) + :modes (emacs-lisp-mode lisp-interaction-mode) + :enabled flycheck--emacs-lisp-enabled-p + :predicate + (lambda () + ;; Do not check buffers that should not be byte-compiled. The checker + ;; process will refuse to compile these, which would confuse Flycheck + (not (bound-and-true-p no-byte-compile))) + :next-checkers (emacs-lisp-checkdoc)) + +(defconst flycheck-emacs-lisp-checkdoc-form + (flycheck-prepare-emacs-lisp-form + (unless (require 'elisp-mode nil 'no-error) + ;; TODO: Fallback for Emacs 24, remove when dropping support for 24 + (require 'lisp-mode)) + (require 'checkdoc) + + (let ((source (car command-line-args-left)) + ;; Remember the default directory of the process + (process-default-directory default-directory)) + ;; Note that we deliberately use our custom approach even despite of + ;; `checkdoc-file' which was added to Emacs 25.1. While it's conceptually + ;; the better thing, its implementation has too many flaws to be of use + ;; for us. + (with-temp-buffer + (insert-file-contents source 'visit) + (setq buffer-file-name source) + ;; And change back to the process default directory to make file-name + ;; back-substutition work + (setq default-directory process-default-directory) + (with-demoted-errors "Error in checkdoc: %S" + ;; Checkdoc needs the Emacs Lisp syntax table and comment syntax to + ;; parse sexps and identify docstrings correctly; see + ;; https://github.com/flycheck/flycheck/issues/833 + (delay-mode-hooks (emacs-lisp-mode)) + (setq delayed-mode-hooks nil) + (checkdoc-current-buffer t) + (with-current-buffer checkdoc-diagnostic-buffer + (princ (buffer-substring-no-properties (point-min) (point-max))) + (kill-buffer))))))) + +(defconst flycheck-emacs-lisp-checkdoc-variables + '(checkdoc-symbol-words + checkdoc-arguments-in-order-flag + checkdoc-force-history-flag + checkdoc-permit-comma-termination-flag + checkdoc-force-docstrings-flag + checkdoc-package-keywords-flag + checkdoc-spellcheck-documentation-flag + checkdoc-verb-check-experimental-flag + checkdoc-max-keyref-before-warn + sentence-end-double-space) + "Variables inherited by the checkdoc subprocess.") + +(defun flycheck-emacs-lisp-checkdoc-variables-form () + "Make a sexp to pass relevant variables to a checkdoc subprocess. + +Variables are taken from `flycheck-emacs-lisp-checkdoc-variables'." + `(progn + ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt))) + (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables)))) + +(flycheck-define-checker emacs-lisp-checkdoc + "An Emacs Lisp style checker using CheckDoc. + +The checker runs `checkdoc-current-buffer'." + :command ("emacs" (eval flycheck-emacs-args) + "--eval" (eval (flycheck-sexp-to-string + (flycheck-emacs-lisp-checkdoc-variables-form))) + "--eval" (eval flycheck-emacs-lisp-checkdoc-form) + "--" source) + :error-patterns + ((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)) + +(defun flycheck-ember-template--check-for-config (&rest _ignored) + "Check the required config file is available up the file system." + (and buffer-file-name + (locate-dominating-file buffer-file-name ".template-lintrc.js"))) + +(defun flycheck-ember-template--parse-error (output checker buffer) + "Parse Ember-template-lint errors/warnings from JSON OUTPUT. +CHECKER and BUFFER denote the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at + .line + .column + (pcase .severity + (2 'error) + (1 'warning) + (_ 'warning)) + .message + :id .rule + :checker checker + :buffer buffer + :filename (buffer-file-name buffer)))) + (cdr (car (car (flycheck-parse-json output)))))) + +(flycheck-def-config-file-var flycheck-ember-template-lintrc + ember-template + ".template-lintrc.js") + +(flycheck-define-checker ember-template + "An Ember template checker using ember-template-lint." + :command ("ember-template-lint" + (config-file "--config-path" flycheck-ember-template-lintrc) + "--filename" source-original + "--json") + :standard-input t + :error-parser flycheck-ember-template--parse-error + :modes web-mode + :enabled flycheck-ember-template--check-for-config + :working-directory flycheck-ember-template--check-for-config) + +(flycheck-def-option-var flycheck-erlang-include-path nil erlang + "A list of include directories for Erlang. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of erlc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-erlang-library-path nil erlang + "A list of library directories for Erlang. + +The value of this variable is a list of strings, where each +string is a directory to add to the library path of erlc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Library directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker erlang + "An Erlang syntax checker using the Erlang interpreter. + +See URL `http://www.erlang.org/'." + :command ("erlc" + "-o" temporary-directory + (option-list "-I" flycheck-erlang-include-path) + (option-list "-pa" flycheck-erlang-library-path) + "-Wall" + source) + :error-patterns + ((warning line-start (file-name) ":" line ": Warning:" (message) line-end) + (error line-start (file-name) ":" line ": " (message) line-end)) + :modes erlang-mode + :enabled (lambda () (string-suffix-p ".erl" (buffer-file-name)))) + +(defun flycheck--contains-rebar-config (dir-name) + "Return DIR-NAME if rebar config file exists in DIR-NAME, nil otherwise." + (when (or (file-exists-p (expand-file-name "rebar.config" dir-name)) + (file-exists-p (expand-file-name "rebar.config.script" dir-name))) + dir-name)) + +(defun flycheck--locate-rebar3-project-root + (file-name &optional prev-file-name acc) + "Find the top-most rebar project root for source FILE-NAME. + +A project root directory is any directory containing a +rebar.config file. Find the top-most directory to move out of any +nested dependencies. + +FILE-NAME is a source file for which to find the project. + +PREV-FILE-NAME helps us prevent infinite looping + +ACC is an accumulator that keeps the list of results, the first +non-nil of which will be our project root. + +Return the absolute path to the directory" + (if (string= file-name prev-file-name) + (car (remove nil acc)) + (let ((current-dir (file-name-directory file-name))) + (flycheck--locate-rebar3-project-root + (directory-file-name current-dir) + file-name + (cons (flycheck--contains-rebar-config current-dir) acc))))) + +(defun flycheck-rebar3-project-root (&optional _checker) + "Return directory where rebar.config is located." + (flycheck--locate-rebar3-project-root buffer-file-name)) + +(flycheck-def-option-var flycheck-erlang-rebar3-profile nil erlang-rebar3 + "The rebar3 profile to use. + +The profile used when compiling, if VALUE is nil \"test\" will be used +when the file is located in test directory, otherwise \"default\" will be +used as profile." + :type '(choice (const :tag "Automatic" nil) + (string :tag "Profile")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) + +(defun flycheck-erlang-rebar3-get-profile () + "Return rebar3 profile. + +Use flycheck-erlang-rebar3-profile if set, otherwise use test or eqc profile if +directory name is \"test\" or \"eqc\", or else \"default\"." + (or + flycheck-erlang-rebar3-profile + (with-no-warnings + ;; `seq-contains-p' is only in seq >= 2.21 + (seq-contains '("test" "eqc") + (and buffer-file-name + (file-name-base + (directory-file-name + (file-name-directory buffer-file-name)))))) + "default")) + +(flycheck-define-checker erlang-rebar3 + "An Erlang syntax checker using the rebar3 build tool." + :command ("rebar3" "as" (eval (flycheck-erlang-rebar3-get-profile)) "compile") + :error-parser flycheck-parse-with-patterns-without-color + :error-patterns + ((warning line-start + (file-name) ":" line ": Warning:" (message) line-end) + (error line-start + (file-name) ":" line ": " (message) line-end)) + :modes erlang-mode + :enabled flycheck-rebar3-project-root + :predicate flycheck-buffer-saved-p + :working-directory flycheck-rebar3-project-root) + +(flycheck-define-checker eruby-erubis + "An eRuby syntax checker using the `erubis' command. + +See URL `http://www.kuwata-lab.com/erubis/'." + :command ("erubis" "-z" source) + :error-patterns + ((error line-start (file-name) ":" line ": " (message) line-end)) + :modes (html-erb-mode rhtml-mode) + :next-checkers ((warning . eruby-ruumba))) + +(flycheck-def-config-file-var flycheck-ruumbarc eruby-ruumba ".ruumba.yml") + +(flycheck-def-option-var flycheck-ruumba-lint-only nil eruby-ruumba + "Whether to only report code issues in Ruumba. + +When non-nil, only report code issues in Ruumba, via `--lint'. +Otherwise report style issues as well." + :safe #'booleanp + :type 'boolean + :package-version '(flycheck . "32")) + +(flycheck-define-checker eruby-ruumba + "An eRuby syntax and style checker using the Ruumba tool. + +You need at least Ruumba 0.1.7 for this syntax checker. + +See URL `https://github.com/ericqweinstein/ruumba'." + :command ("ruumba" + "--display-cop-names" + "--force-exclusion" + "--format" "emacs" + "--cache" "false" + (config-file "--config" flycheck-ruumbarc) + (option-flag "--lint" flycheck-ruumba-lint-only) + ;; Ruumba takes the original file name as argument when reading + ;; from standard input + "--stdin" source-original) + :standard-input t + :working-directory flycheck-ruby--find-project-root + :error-patterns + ((info line-start (file-name) ":" line ":" column ": C: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end) + (warning line-start (file-name) ":" line ":" column ": W: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end) + (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end)) + :modes (html-erb-mode rhtml-mode)) + +(flycheck-def-args-var flycheck-gfortran-args fortran-gfortran + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-gfortran-include-path nil fortran-gfortran + "A list of include directories for GCC Fortran. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of gcc. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gfortran-language-standard "f95" + fortran-gfortran + "The language standard to use in GFortran. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `-std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :package-version '(flycheck . "0.20")) + +(flycheck-def-option-var flycheck-gfortran-layout nil fortran-gfortran + "The source code layout to use in GFortran. + +The value of this variable is one of the following symbols: + +nil + Let gfortran determine the layout from the extension + +`free' + Use free form layout + + +`fixed' + Use fixed form layout + +In any other case, an error is signaled." + :type '(choice (const :tag "Guess layout from extension" nil) + (const :tag "Free form layout" free) + (const :tag "Fixed form layout" fixed)) + :safe (lambda (value) (or (not value) (memq value '(free fixed)))) + :package-version '(flycheck . "0.20")) + +(defun flycheck-option-gfortran-layout (value) + "Option VALUE filter for `flycheck-gfortran-layout'." + (pcase value + (`nil nil) + (`free "free-form") + (`fixed "fixed-form") + (_ (error "Invalid value for flycheck-gfortran-layout: %S" value)))) + +(flycheck-def-option-var flycheck-gfortran-warnings '("all" "extra") + fortran-gfortran + "A list of warnings for GCC Fortran. + +The value of this variable is a list of strings, where each string +is the name of a warning category to enable. By default, all +recommended warnings and some extra warnings are enabled (as by +`-Wall' and `-Wextra' respectively). + +Refer to the gfortran manual at URL +`https://gcc.gnu.org/onlinedocs/gfortran/' for more information +about warnings" + :type '(choice (const :tag "No additional warnings" nil) + (repeat :tag "Additional warnings" + (string :tag "Warning name"))) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker fortran-gfortran + "An Fortran syntax checker using GCC. + +Uses GCC's Fortran compiler gfortran. See URL +`https://gcc.gnu.org/onlinedocs/gfortran/'." + :command ("gfortran" + "-fsyntax-only" + "-fshow-column" + ;; Do not visually indicate the source location + "-fno-diagnostics-show-caret" + ;; Do not show the corresponding warning group + "-fno-diagnostics-show-option" + ;; Fortran has similar include processing as C/C++ + "-iquote" (eval (flycheck-c/c++-quoted-include-directory)) + (option "-std=" flycheck-gfortran-language-standard concat) + (option "-f" flycheck-gfortran-layout concat + flycheck-option-gfortran-layout) + (option-list "-W" flycheck-gfortran-warnings concat) + (option-list "-I" flycheck-gfortran-include-path concat) + (eval flycheck-gfortran-args) + source) + :error-patterns + ((error line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n") + (or (= 3 (zero-or-more not-newline) "\n") "") + (or "Error" "Fatal Error") ": " + (message) line-end) + (warning line-start (file-name) ":" line (or ":" ".") column (or ": " ":\n") + (or (= 3 (zero-or-more not-newline) "\n") "") + "Warning: " (message) line-end)) + :modes (fortran-mode f90-mode)) + +(flycheck-define-checker go-gofmt + "A Go syntax and style checker using the gofmt utility. + +See URL `https://golang.org/cmd/gofmt/'." + :command ("gofmt") + :standard-input t + :error-patterns + ((error line-start ":" line ":" column ": " + (message) line-end)) + :modes go-mode + :next-checkers ((warning . go-golint) + ;; Fall back, if go-golint doesn't exist + (warning . go-vet) + ;; Fall back, if go-vet doesn't exist + (warning . go-build) (warning . go-test) + (warning . go-errcheck) + (warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-golint + "A Go style checker using Golint. + +See URL `https://github.com/golang/lint'." + :command ("golint" source) + :error-patterns + ((warning line-start (file-name) ":" line ":" column ": " (message) line-end)) + :modes go-mode + :next-checkers (go-vet + ;; Fall back, if go-vet doesn't exist + go-build go-test go-errcheck go-unconvert)) + +(flycheck-def-option-var flycheck-go-vet-print-functions nil go-vet + "A list of print-like functions for `go vet'. + +Go vet will check these functions for format string problems and +issues, such as a mismatch between the number of formats used, +and the number of arguments given. + +Each entry is in the form Name:N where N is the zero-based +argument position of the first argument involved in the print: +either the format or the first print argument for non-formatted +prints. For example, if you have Warn and Warnf functions that +take an io.Writer as their first argument, like Fprintf, +-printfuncs=Warn:1,Warnf:1 " + :type '(repeat :tag "print-like functions" + (string :tag "function")) + :safe #'flycheck-string-list-p) + +(flycheck-define-checker go-vet + "A Go syntax checker using the `go vet' command. + +See URL `https://golang.org/cmd/go/' and URL +`https://golang.org/cmd/vet/'." + :command ("go" "vet" + (option "-printf.funcs=" flycheck-go-vet-print-functions concat + flycheck-option-comma-separated-list) + source) + :error-patterns + ((warning line-start (file-name) ":" line ": " (message) line-end)) + :modes go-mode + :next-checkers (go-build + go-test + ;; Fall back if `go build' or `go test' can be used + go-errcheck + go-unconvert + go-staticcheck) + :verify (lambda (_) + (let* ((go (flycheck-checker-executable 'go-vet)) + (have-vet (member "vet" (ignore-errors + (process-lines go "tool"))))) + (list + (flycheck-verification-result-new + :label "go tool vet" + :message (if have-vet "present" "missing") + :face (if have-vet 'success '(bold error))))))) + +(flycheck-def-option-var flycheck-go-build-install-deps nil (go-build go-test) + "Whether to install dependencies in `go build' and `go test'. + +If non-nil automatically install dependencies with `go build' +while syntax checking." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.25")) + +(flycheck-def-option-var flycheck-go-build-tags nil + (go-build go-test go-errcheck go-staticcheck) + "A list of tags for `go build'. + +Each item is a string with a tag to be given to `go build'." + :type '(repeat (string :tag "Tag")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.25")) + + +(flycheck-def-option-var flycheck-go-version nil go-staticcheck + "The version of go that should be targeted by `staticcheck'. + +Should be a string representing a version, like 1.6 or 1.11.4. +See `https://staticcheck.io/docs/#targeting-go-versions' for +details." + :type '(choice (const :tag "Unspecified" nil) + (string :tag "Version")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.32")) + +(flycheck-define-checker go-build + "A Go syntax and type checker using the `go build' command. + +Requires Go 1.6 or newer. See URL `https://golang.org/cmd/go'." + :command ("go" "build" + (option-flag "-i" flycheck-go-build-install-deps) + ;; multiple tags are listed as "dev debug ..." + (option-list "-tags=" flycheck-go-build-tags concat) + "-o" null-device) + :error-patterns + ((error line-start (file-name) ":" line ":" + (optional column ":") " " + (message (one-or-more not-newline) + (zero-or-more "\n\t" (one-or-more not-newline))) + line-end) + ;; Catch error message about multiple packages in a directory, which doesn't + ;; follow the standard error message format. + (info line-start + (message "can't load package: package " + (one-or-more (not (any ?: ?\n))) + ": found packages " + (one-or-more not-newline)) + line-end)) + :error-filter + (lambda (errors) + (dolist (error errors) + (unless (flycheck-error-line error) + ;; Flycheck ignores errors without line numbers, but the error + ;; message about multiple packages in a directory doesn't come with a + ;; line number, so inject a fake one. + (setf (flycheck-error-line error) 1))) + errors) + :modes go-mode + :predicate (lambda () + (and (flycheck-buffer-saved-p) + (not (string-suffix-p "_test.go" (buffer-file-name))))) + :next-checkers ((warning . go-errcheck) + (warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-test + "A Go syntax and type checker using the `go test' command. + +Requires Go 1.6 or newer. See URL `https://golang.org/cmd/go'." + :command ("go" "test" + (option-flag "-i" flycheck-go-build-install-deps) + (option-list "-tags=" flycheck-go-build-tags concat) + "-c" "-o" null-device) + :error-patterns + ((error line-start (file-name) ":" line ":" + (optional column ":") " " + (message (one-or-more not-newline) + (zero-or-more "\n\t" (one-or-more not-newline))) + line-end)) + :modes go-mode + :predicate + (lambda () (and (flycheck-buffer-saved-p) + (string-suffix-p "_test.go" (buffer-file-name)))) + :next-checkers ((warning . go-errcheck) + (warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-errcheck + "A Go checker for unchecked errors. + +Requires errcheck newer than commit 8515d34 (Aug 28th, 2015). + +See URL `https://github.com/kisielk/errcheck'." + :command ("errcheck" + "-abspath" + (option-list "-tags=" flycheck-go-build-tags concat) + ".") + :error-patterns + ((warning line-start + (file-name) ":" line ":" column (or (one-or-more "\t") ": " ":\t") + (message) + line-end)) + :error-filter + (lambda (errors) + (let ((errors (flycheck-sanitize-errors errors))) + (dolist (err errors) + (-when-let (message (flycheck-error-message err)) + ;; Improve the messages reported by errcheck to make them more clear. + (setf (flycheck-error-message err) + (format "Ignored `error` returned from `%s`" message))))) + errors) + :modes go-mode + :predicate (lambda () (flycheck-buffer-saved-p)) + :next-checkers ((warning . go-unconvert) + (warning . go-staticcheck))) + +(flycheck-define-checker go-unconvert + "A Go checker looking for unnecessary type conversions. + +See URL `https://github.com/mdempsky/unconvert'." + :command ("unconvert" ".") + :error-patterns + ((warning line-start (file-name) ":" line ":" column ": " (message) line-end)) + :modes go-mode + :predicate (lambda () (flycheck-buffer-saved-p))) + +(flycheck-define-checker go-staticcheck + "A Go checker that performs static analysis and linting using +the `staticcheck' command. + +`staticcheck' is explicitly fully compatible with \"the last two +versions of go\". `staticheck' can target earlier versions (with +limited features) if `flycheck-go-version' is set. See URL +`https://staticcheck.io/'." + :command ("staticcheck" "-f" "json" + (option-list "-tags" flycheck-go-build-tags concat) + (option "-go" flycheck-go-version)) + + :error-parser flycheck-parse-go-staticcheck + :modes go-mode) + +(flycheck-define-checker groovy + "A groovy syntax checker using groovy compiler API. + +See URL `http://www.groovy-lang.org'." + :command ("groovy" "-e" + "import org.codehaus.groovy.control.* + +unit = new CompilationUnit() +unit.addSource(\"input\", System.in) + +try { + unit.compile(Phases.CONVERSION) +} catch (MultipleCompilationErrorsException e) { + e.errorCollector.write(new PrintWriter(System.out, true), null) +}") + :standard-input t + :error-patterns + ((error line-start "input: " line ":" (message) + " @ line " line ", column " column "." line-end)) + :modes groovy-mode) + +(flycheck-define-checker haml + "A Haml syntax checker using the Haml compiler. + +See URL `http://haml.info'." + :command ("haml" "-c" "--stdin") + :standard-input t + :error-patterns + ((error line-start "Syntax error on line " line ": " (message) line-end) + (error line-start ":" line ": syntax error, " (message) line-end)) + :modes haml-mode) + +(flycheck-define-checker handlebars + "A Handlebars syntax checker using the Handlebars compiler. + +See URL `http://handlebarsjs.com/'." + :command ("handlebars" "-i-") + :standard-input t + :error-patterns + ((error line-start + "Error: Parse error on line " line ":" (optional "\r") "\n" + (zero-or-more not-newline) "\n" (zero-or-more not-newline) "\n" + (message) line-end)) + :modes (handlebars-mode handlebars-sgml-mode web-mode) + :predicate + (lambda () + (if (eq major-mode 'web-mode) + ;; Check if this is a handlebars file since web-mode does not store the + ;; non-canonical engine name + (let* ((regexp-alist (bound-and-true-p web-mode-engine-file-regexps)) + (pattern (cdr (assoc "handlebars" regexp-alist)))) + (and pattern (buffer-file-name) + (string-match-p pattern (buffer-file-name)))) + t))) + +(defconst flycheck-haskell-module-re + (rx line-start (zero-or-more (or "\n" (any space))) + "module" (one-or-more (or "\n" (any space))) + (group (one-or-more (not (any space "(" "\n"))))) + "Regular expression for a Haskell module name.") + +(flycheck-def-args-var flycheck-ghc-args (haskell-stack-ghc haskell-ghc) + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-ghc-stack-use-nix nil haskell-stack-ghc + "Whether to enable nix support in stack. + +When non-nil, stack will append '--nix' flag to any call." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "26")) + +(flycheck-def-option-var flycheck-ghc-stack-project-file nil haskell-stack-ghc + "Override project stack.yaml file. + +The value of this variable is a file path that refers to a yaml +file for the current stack project. Relative file paths are +resolved against the checker's working directory. When non-nil, +stack will get overridden value via `--stack-yaml'." + :type '(choice (const :tag "Unspecified" nil) + (file :tag "Project file")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-ghc-no-user-package-database nil haskell-ghc + "Whether to disable the user package database in GHC. + +When non-nil, disable the user package database in GHC, via +`-no-user-package-db'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-ghc-package-databases nil haskell-ghc + "Additional module databases for GHC. + +The value of this variable is a list of strings, where each +string is a directory of a package database. Each package +database is given to GHC via `-package-db'." + :type '(repeat (directory :tag "Package database")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-ghc-search-path nil + (haskell-stack-ghc haskell-ghc) + "Module search path for (Stack) GHC. + +The value of this variable is a list of strings, where each +string is a directory containing Haskell modules. Each directory +is added to the GHC search path via `-i'." + :type '(repeat (directory :tag "Module directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.16")) + +(flycheck-def-option-var flycheck-ghc-language-extensions nil + (haskell-stack-ghc haskell-ghc) + "Language extensions for (Stack) GHC. + +The value of this variable is a list of strings, where each +string is a Haskell language extension, as in the LANGUAGE +pragma. Each extension is enabled via `-X'." + :type '(repeat (string :tag "Language extension")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.19")) + +(defvar flycheck-haskell-ghc-cache-directory nil + "The cache directory for `ghc' output.") + +(defun flycheck-haskell-ghc-cache-directory () + "Get the cache location for `ghc' output. + +If no cache directory exists yet, create one and return it. +Otherwise return the previously used cache directory." + (setq flycheck-haskell-ghc-cache-directory + (or flycheck-haskell-ghc-cache-directory + (make-temp-file "flycheck-haskell-ghc-cache" 'directory)))) + +(defun flycheck--locate-dominating-file-matching (directory regexp) + "Search for a file in directory hierarchy starting at DIRECTORY. + +Look up the directory hierarchy from DIRECTORY for a directory +containing a file that matches REGEXP." + (locate-dominating-file + directory + (lambda (dir) + (directory-files dir nil regexp t)))) + +(defun flycheck-haskell--find-stack-default-directory () + "Find a directory to run haskell-stack-ghc. + +Return a parent directory with a stack*.y[a]ml file, or the +directory returned by \"stack path --project-root\"." + (or + (when (buffer-file-name) + (flycheck--locate-dominating-file-matching + (file-name-directory (buffer-file-name)) + (rx "stack" (* any) "." (or "yml" "yaml") eos))) + (-when-let* ((stack (funcall flycheck-executable-find "stack")) + (output (ignore-errors + (process-lines stack + "--no-install-ghc" + "path" "--project-root"))) + (stack-dir (car output))) + (and (file-directory-p stack-dir) stack-dir)))) + +(defun flycheck-haskell--ghc-find-default-directory (_checker) + "Find a parent directory containing a cabal or package.yaml file." + (when (buffer-file-name) + (flycheck--locate-dominating-file-matching + (file-name-directory (buffer-file-name)) + "\\.cabal\\'\\|\\`package\\.yaml\\'"))) + +(flycheck-define-checker haskell-stack-ghc + "A Haskell syntax and type checker using `stack ghc'. + +See URL `https://github.com/commercialhaskell/stack'." + :command ("stack" + "--no-install-ghc" + (option "--stack-yaml" flycheck-ghc-stack-project-file) + (option-flag "--nix" flycheck-ghc-stack-use-nix) + "ghc" "--" "-Wall" "-no-link" + "-outputdir" (eval (flycheck-haskell-ghc-cache-directory)) + (option-list "-X" flycheck-ghc-language-extensions concat) + (option-list "-i" flycheck-ghc-search-path concat) + (eval (concat + "-i" + (flycheck-module-root-directory + (flycheck-find-in-buffer flycheck-haskell-module-re)))) + (eval flycheck-ghc-args) + "-x" (eval + (pcase major-mode + (`haskell-mode "hs") + (`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 (lambda (_) + (flycheck-haskell--find-stack-default-directory)) + :enabled flycheck-haskell--find-stack-default-directory + :verify (lambda (_) + (let* ((stack (flycheck-haskell--find-stack-default-directory))) + (list + (flycheck-verification-result-new + :label "stack config" + :message (or stack "Not found") + :face (if stack 'success '(bold error))))))) + +(flycheck-define-checker haskell-ghc + "A Haskell syntax and type checker using ghc. + +See URL `https://www.haskell.org/ghc/'." + :command ("ghc" "-Wall" "-no-link" + "-outputdir" (eval (flycheck-haskell-ghc-cache-directory)) + (option-flag "-no-user-package-db" + flycheck-ghc-no-user-package-database) + (option-list "-package-db" flycheck-ghc-package-databases) + (option-list "-i" flycheck-ghc-search-path concat) + ;; Include the parent directory of the current module tree, to + ;; properly resolve local imports + (eval (concat + "-i" + (flycheck-module-root-directory + (flycheck-find-in-buffer flycheck-haskell-module-re)))) + (option-list "-X" flycheck-ghc-language-extensions concat) + (eval flycheck-ghc-args) + "-x" (eval + (pcase major-mode + (`haskell-mode "hs") + (`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--ghc-find-default-directory) + +(flycheck-def-config-file-var flycheck-hlintrc haskell-hlint "HLint.hs") + +(flycheck-def-args-var flycheck-hlint-args haskell-hlint + :package-version '(flycheck . "0.25")) + +(flycheck-def-option-var flycheck-hlint-language-extensions + nil haskell-hlint + "Extensions list to enable for hlint. + +The value of this variable is a list of strings, where each +string is a name of extension to enable in +hlint (e.g. \"QuasiQuotes\")." + :type '(repeat :tag "Extensions" (string :tag "Extension")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-hlint-ignore-rules + nil haskell-hlint + "Ignore rules list for hlint checks. + +The value of this variable is a list of strings, where each +string is an ignore rule (e.g. \"Use fmap\")." + :type '(repeat :tag "Ignore rules" (string :tag "Ignore rule")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-hlint-hint-packages + nil haskell-hlint + "Hint packages to include for hlint checks. + +The value of this variable is a list of strings, where each +string is a default hint package (e.g. (\"Generalise\" +\"Default\" \"Dollar\"))." + :type '(repeat :tag "Hint packages" (string :tag "Hint package")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker haskell-hlint + "A Haskell style checker using hlint. + +See URL `https://github.com/ndmitchell/hlint'." + :command ("hlint" + (option-list "-X" flycheck-hlint-language-extensions concat) + (option-list "-i=" flycheck-hlint-ignore-rules concat) + (option-list "-h" flycheck-hlint-hint-packages concat) + (config-file "-h" flycheck-hlintrc) + (eval flycheck-hlint-args) + source-inplace) + :error-patterns + ((info line-start + (file-name) ":" line ":" column + ": 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") + +(flycheck-define-checker html-tidy + "A HTML syntax and style checker using Tidy. + +See URL `https://github.com/htacg/tidy-html5'." + :command ("tidy" (config-file "-config" flycheck-tidyrc) + "-lang" "en" + "-e" "-q") + :standard-input t + :error-patterns + ((error line-start + "line " line + " column " column + " - Error: " (message) line-end) + (warning line-start + "line " line + " column " column + " - Warning: " (message) line-end)) + :modes (html-mode mhtml-mode nxhtml-mode)) + +(flycheck-def-config-file-var flycheck-jshintrc javascript-jshint ".jshintrc") + +(flycheck-def-option-var flycheck-jshint-extract-javascript nil + javascript-jshint + "Whether jshint should extract Javascript from HTML. + +If nil no extract rule is given to jshint. If `auto' only +extract Javascript if a HTML file is detected. If `always' or +`never' extract Javascript always or never respectively. + +Refer to the jshint manual at the URL +`http://jshint.com/docs/cli/#flags' for more information." + :type + '(choice (const :tag "No extraction rule" nil) + (const :tag "Try to extract Javascript when detecting HTML files" + auto) + (const :tag "Always try to extract Javascript" always) + (const :tag "Never try to extract Javascript" never)) + :safe #'symbolp + :package-version '(flycheck . "26")) + +(flycheck-define-checker javascript-jshint + "A Javascript syntax and style checker using jshint. + +See URL `http://www.jshint.com'." + :command ("jshint" "--reporter=checkstyle" + "--filename" source-original + (config-file "--config" flycheck-jshintrc) + (option "--extract=" flycheck-jshint-extract-javascript + concat flycheck-option-symbol) + "-") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter + (lambda (errors) + (flycheck-remove-error-file-names + "stdin" (flycheck-dequalify-error-ids errors))) + :modes (js-mode js2-mode js3-mode rjsx-mode)) + +(flycheck-def-args-var flycheck-eslint-args javascript-eslint + :package-version '(flycheck . "32")) + +(flycheck-def-option-var flycheck-eslint-rules-directories nil javascript-eslint + "A list of directories with custom rules for ESLint. + +The value of this variable is a list of strings, where each +string is a directory with custom rules for ESLint. + +Refer to the ESLint manual at URL +`http://eslint.org/docs/user-guide/command-line-interface#--rulesdir' +for more information about the custom directories." + :type '(repeat (directory :tag "Custom rules directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "29")) + +(defun flycheck-eslint-config-exists-p () + "Whether there is a valid eslint config for the current buffer." + (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) + :end-line .endLine + :end-column .endColumn))) + (let-alist (caar (flycheck-parse-json output)) + .messages))) + +(defun flycheck-eslint--find-working-directory (_checker) + "Look for a working directory to run ESLint CHECKER in. + +This will be the directory that contains the `node_modules' +directory. If no such directory is found in the directory +hierarchy, it looks first for `.eslintignore' and then for +`.eslintrc' files to detect the project root." + (let* ((regex-config (concat "\\`\\.eslintrc" + "\\(\\.\\(js\\|ya?ml\\|json\\)\\)?\\'"))) + (when buffer-file-name + (or (locate-dominating-file buffer-file-name "node_modules") + (locate-dominating-file buffer-file-name ".eslintignore") + (locate-dominating-file + (file-name-directory buffer-file-name) + (lambda (directory) + (> (length (directory-files directory nil regex-config t)) 0))))))) + +(flycheck-define-checker javascript-eslint + "A Javascript syntax and style checker using eslint. + +See URL `https://eslint.org/'." + :command ("eslint" "--format=json" + (option-list "--rulesdir" flycheck-eslint-rules-directories) + (eval flycheck-eslint-args) + "--stdin" "--stdin-filename" source-original) + :standard-input t + :error-parser flycheck-parse-eslint + :enabled (lambda () (flycheck-eslint-config-exists-p)) + :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode + typescript-mode) + :working-directory flycheck-eslint--find-working-directory + :verify + (lambda (_) + (let* ((default-directory + (flycheck-compute-working-directory 'javascript-eslint)) + (have-config (flycheck-eslint-config-exists-p))) + (list + (flycheck-verification-result-new + :label "config file" + :message (if have-config "found" "missing or incorrect") + :face (if have-config 'success '(bold error))))))) + +(flycheck-define-checker javascript-standard + "A Javascript code and style checker for the (Semi-)Standard Style. + +This checker works with `standard' and `semistandard', defaulting +to the former. To use it with the latter, set +`flycheck-javascript-standard-executable' to `semistandard'. + +See URL `https://github.com/standard/standard' and URL +`https://github.com/Flet/semistandard'." + :command ("standard" "--stdin") + :standard-input t + :error-patterns + ((error line-start " :" line ":" column ":" (message) line-end)) + :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode)) + +(flycheck-define-checker json-jsonlint + "A JSON syntax and style checker using jsonlint. + +See URL `https://github.com/zaach/jsonlint'." + ;; We can't use standard input for jsonlint, because it doesn't output errors + ;; anymore when using -c -q with standard input :/ + :command ("jsonlint" "-c" "-q" source) + :error-patterns + ((error line-start + (file-name) + ": line " line + ", col " column ", " + (message) line-end)) + :error-filter + (lambda (errors) + (flycheck-sanitize-errors (flycheck-increment-error-columns errors))) + :modes json-mode) + +(flycheck-define-checker json-python-json + "A JSON syntax checker using Python json.tool module. + +See URL `https://docs.python.org/3.5/library/json.html#command-line-interface'." + :command ("python3" "-m" "json.tool" source + ;; Send the pretty-printed output to the null device + null-device) + :error-patterns + ((error line-start + (message) ": line " line " column " column + ;; Ignore the rest of the line which shows the char position. + (one-or-more not-newline) + line-end)) + :modes json-mode + ;; The JSON parser chokes if the buffer is empty and has no JSON inside + :predicate flycheck-buffer-nonempty-p) + +(flycheck-define-checker json-jq + "JSON checker using the jq tool. + +This checker accepts multiple consecutive JSON values in a +single input, which is useful for jsonlines data. + +See URL `https://stedolan.github.io/jq/'." + :command ("jq" "." source null-device) + ;; Example error message: + ;; parse error: Expected another key-value pair at line 3, column 1 + :error-patterns + ((error line-start + (optional "parse error: ") + (message) "at line " line ", column " column + (zero-or-more not-newline) line-end)) + :modes json-mode) + +(flycheck-define-checker jsonnet + "A Jsonnet syntax checker using the jsonnet binary. + +See URL `https://jsonnet.org'." + :command ("jsonnet" source-inplace) + :error-patterns + ((error line-start "STATIC ERROR: " (file-name) ":" + (or (seq line ":" column (zero-or-one (seq "-" end-column))) + (seq "(" line ":" column ")" "-" + "(" end-line ":" end-column ")")) + ": " (message) line-end) + (error line-start "RUNTIME ERROR: " (message) "\n" + (? "\t" (file-name) ":" ;; first line of the backtrace + (or (seq line ":" column (zero-or-one (seq "-" end-column))) + (seq "(" line ":" column ")" "-" + "(" end-line ":" end-column ")"))))) + :error-filter + (lambda (errs) + ;; Some errors are missing line numbers. See URL + ;; `https://github.com/google/jsonnet/issues/786'. + (dolist (err errs) + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 1))) + (flycheck-sanitize-errors errs)) + :modes jsonnet-mode) + +(flycheck-define-checker less + "A LESS syntax checker using lessc. + +Requires lessc 1.4 or newer. + +See URL `http://lesscss.org'." + :command ("lessc" "--lint" "--no-color" + "-") + :standard-input t + :error-patterns + ((error line-start (one-or-more word) ":" + (message) + " in - on line " line + ", column " column ":" + line-end)) + :modes less-css-mode) + +(flycheck-define-checker less-stylelint + "A LESS syntax and style checker using stylelint. + +See URL `http://stylelint.io/'." + :command ("stylelint" + (eval flycheck-stylelint-args) + "--syntax" "less" + (option-flag "--quiet" flycheck-stylelint-quiet) + (config-file "--config" flycheck-stylelintrc)) + :standard-input t + :error-parser flycheck-parse-stylelint + :predicate flycheck-buffer-nonempty-p + :modes (less-css-mode)) + +(flycheck-define-checker llvm-llc + "Flycheck LLVM IR checker using llc. + +See URL `http://llvm.org/docs/CommandGuide/llc.html'." + :command ("llc" "-o" null-device source) + :error-patterns + ((error line-start + ;; llc prints the executable path + (zero-or-one (minimal-match (one-or-more not-newline)) ": ") + (file-name) ":" line ":" column ": error: " (message) + line-end)) + :error-filter + (lambda (errors) + ;; sanitize errors occurring in inline assembly + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "" errors))) + :modes llvm-mode) + +(flycheck-def-config-file-var flycheck-luacheckrc lua-luacheck ".luacheckrc") + +(flycheck-def-option-var flycheck-luacheck-standards nil lua-luacheck + "The standards to use in luacheck. + +The value of this variable is either a list of strings denoting +the standards to use, or nil to pass nothing to luacheck. When +non-nil, pass the standards via one or more `--std' options." + :type '(choice (const :tag "Default" nil) + (repeat :tag "Custom standards" + (string :tag "Standard name"))) + :safe #'flycheck-string-list-p) +(make-variable-buffer-local 'flycheck-luacheck-standards) + +(flycheck-define-checker lua-luacheck + "A Lua syntax checker using luacheck. + +See URL `https://github.com/mpeterv/luacheck'." + :command ("luacheck" + "--formatter" "plain" + "--codes" ; Show warning codes + "--no-color" + (option-list "--std" flycheck-luacheck-standards) + (config-file "--config" flycheck-luacheckrc) + "--filename" source-original + ;; Read from standard input + "-") + :standard-input t + :error-patterns + ((warning line-start + (optional (file-name)) + ":" line ":" column + ": (" (id "W" (one-or-more digit)) ") " + (message) line-end) + (error line-start + (optional (file-name)) + ":" line ":" column ":" + ;; `luacheck' before 0.11.0 did not output codes for errors, hence + ;; the ID is optional here + (optional " (" (id "E" (one-or-more digit)) ") ") + (message) line-end)) + :modes lua-mode) + +(flycheck-define-checker lua + "A Lua syntax checker using the Lua compiler. + +See URL `http://www.lua.org/'." + :command ("luac" "-p" "-") + :standard-input t + :error-patterns + ((error line-start + ;; Skip the name of the luac executable. + (minimal-match (zero-or-more not-newline)) + ": stdin:" line ": " (message) line-end)) + :modes lua-mode) + +(flycheck-define-checker opam + "A Opam syntax and style checker using opam lint. + +See URL `https://opam.ocaml.org/doc/man/opam-lint.html'." + :command ("opam" "lint" "-") + :standard-input t + :error-patterns + ((error line-start ; syntax error + (one-or-more space) "error " (id ?2) + ": File format error" + (or (and " at line " line ", column " column ": " (message)) + (and ": " (message))) + line-end) + (error line-start + (one-or-more space) "error " (id ?3) + (minimal-match (zero-or-more not-newline)) + "at line " line ", column " column ": " (message) + line-end) + (error line-start + (one-or-more space) "error " (id (one-or-more num)) + ": " (message (one-or-more not-newline)) + line-end) + (warning line-start + (one-or-more space) "warning " (id (one-or-more num)) + ": " (message) + line-end)) + :error-filter + (lambda (errors) + (flycheck-increment-error-columns + (flycheck-fill-empty-line-numbers errors))) + :modes tuareg-opam-mode) + +(flycheck-def-option-var flycheck-perl-include-path nil perl + "A list of include directories for Perl. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of Perl. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-perl-module-list nil perl + "A list of modules to use for Perl. + +The value of this variable is a list of strings, where each +string is a module to 'use' in Perl." + :type '(repeat :tag "Module") + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker perl + "A Perl syntax checker using the Perl interpreter. + +See URL `https://www.perl.org'." + :command ("perl" "-w" "-c" + (option-list "-I" flycheck-perl-include-path) + (option-list "-M" flycheck-perl-module-list concat)) + :standard-input t + :error-patterns + ((error line-start (minimal-match (message)) + " at - line " line + (or "." (and ", " (zero-or-more not-newline))) line-end)) + :modes (perl-mode cperl-mode) + :next-checkers (perl-perlcritic)) + +(flycheck-def-option-var flycheck-perlcritic-severity nil perl-perlcritic + "The message severity for Perl Critic. + +The value of this variable is a severity level as integer, for +the `--severity' option to Perl Critic." + :type '(integer :tag "Severity level") + :safe #'integerp + :package-version '(flycheck . "0.18")) + +(flycheck-def-option-var flycheck-perlcritic-theme nil perl-perlcritic + "The theme expression for Perl Critic. + +The value of this variable is passed as the `--theme' option to +`Perl::Critic'. See the documentation of `Perl::Critic' for +details." + :type '(choice (const :tag "None" nil) + (string :tag "Theme expression")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32-csv")) + +(flycheck-def-config-file-var flycheck-perlcriticrc perl-perlcritic + ".perlcriticrc" + :package-version '(flycheck . "26")) + +(flycheck-define-checker perl-perlcritic + "A Perl syntax checker using Perl::Critic. + +See URL `https://metacpan.org/pod/Perl::Critic'." + :command ("perlcritic" "--no-color" "--verbose" "%f/%l/%c/%s/%p/%m (%e)\n" + (config-file "--profile" flycheck-perlcriticrc) + (option "--severity" flycheck-perlcritic-severity nil + flycheck-option-int) + (option "--theme" flycheck-perlcritic-theme)) + :standard-input t + :error-patterns + ((info line-start + "STDIN/" line "/" column "/" (any "1") "/" + (id (one-or-more (not (any "/")))) "/" (message) + line-end) + (warning line-start + "STDIN/" line "/" column "/" (any "234") "/" + (id (one-or-more (not (any "/")))) "/" (message) + line-end) + (error line-start + "STDIN/" line "/" column "/" (any "5") "/" + (id (one-or-more (not (any "/")))) "/" (message) + line-end)) + :modes (cperl-mode perl-mode)) + +(flycheck-define-checker php + "A PHP syntax checker using the PHP command line interpreter. + +See URL `http://php.net/manual/en/features.commandline.php'." + :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1" + "-d" "log_errors=0" source) + :error-patterns + ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " " + (message) " in " (file-name) " on line " line line-end)) + :modes (php-mode php+-mode) + :next-checkers ((warning . php-phpmd) + (warning . php-phpcs))) + +(flycheck-def-option-var flycheck-phpmd-rulesets + '("cleancode" "codesize" "controversial" "design" "naming" "unusedcode") + php-phpmd + "The rule sets for PHP Mess Detector. + +Set default rule sets and custom rule set files. + +See section \"Using multiple rule sets\" in the PHP Mess Detector +manual at URL `https://phpmd.org/documentation/index.html'." + :type '(repeat :tag "rule sets" + (string :tag "A filename or rule set")) + :safe #'flycheck-string-list-p) + +(flycheck-define-checker php-phpmd + "A PHP style checker using PHP Mess Detector. + +See URL `https://phpmd.org/'." + :command ("phpmd" source "xml" + (eval (flycheck-option-comma-separated-list + flycheck-phpmd-rulesets))) + :error-parser flycheck-parse-phpmd + :modes (php-mode php+-mode) + :next-checkers (php-phpcs)) + +(flycheck-def-option-var flycheck-phpcs-standard nil php-phpcs + "The coding standard for PHP CodeSniffer. + +When nil, use the default standard from the global PHP +CodeSniffer configuration. When set to a string, pass the string +to PHP CodeSniffer which will interpret it as name as a standard, +or as path to a standard specification." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Standard name or file")) + :safe #'flycheck-string-or-nil-p) + +(flycheck-define-checker php-phpcs + "A PHP style checker using PHP Code Sniffer. + +Needs PHP Code Sniffer 2.6 or newer. + +See URL `http://pear.php.net/package/PHP_CodeSniffer/'." + :command ("phpcs" "--report=checkstyle" + ;; Use -q flag to force quiet mode + ;; Quiet mode prevents errors from extra output when phpcs has + ;; been configured with show_progress enabled + "-q" + (option "--standard=" flycheck-phpcs-standard concat) + ;; Some files are not detected correctly + ;; so it is necessary to pass the extension. + (eval + (-when-let* ((fname buffer-file-name) + (ext (file-name-extension fname))) + (concat "--extensions=" ext))) + + ;; Pass original file name to phpcs. We need to concat explicitly + ;; here, because phpcs really insists to get option and argument as + ;; a single command line argument :| + (eval (when (buffer-file-name) + (concat "--stdin-path=" (buffer-file-name)))) + ;; Read from standard input + "-") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter + (lambda (errors) + (flycheck-sanitize-errors + (flycheck-remove-error-file-names "STDIN" errors))) + :modes (php-mode php+-mode) + ;; phpcs seems to choke on empty standard input, hence skip phpcs if the + ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907 + :predicate flycheck-buffer-nonempty-p) + +(flycheck-define-checker processing + "Processing command line tool. + +See https://github.com/processing/processing/wiki/Command-Line" + :command ("processing-java" "--force" + ;; Don't change the order of these arguments, processing is pretty + ;; picky + (eval (concat "--sketch=" (file-name-directory (buffer-file-name)))) + (eval (concat "--output=" (flycheck-temp-dir-system))) + "--build") + :error-patterns + ((error line-start (file-name) ":" line ":" column + (zero-or-more (or digit ":")) (message) line-end)) + :modes processing-mode + ;; This syntax checker needs a file name + :predicate (lambda () (buffer-file-name))) + +(defun flycheck-proselint-parse-errors (output checker buffer) + "Parse proselint json output errors from OUTPUT. + +CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and +the BUFFER that was checked respectively. + +See URL `http://proselint.com/' for more information about proselint." + (mapcar (lambda (err) + (let-alist err + (flycheck-error-new-at-pos + .start + (pcase .severity + (`"suggestion" 'info) + (`"warning" 'warning) + (`"error" 'error) + ;; Default to error + (_ 'error)) + .message + :id .check + :buffer buffer + :checker checker + ;; See https://github.com/amperser/proselint/issues/1048 + :end-pos .end))) + (let-alist (car (flycheck-parse-json output)) + .data.errors))) + +(flycheck-define-checker proselint + "Flycheck checker using Proselint. + +See URL `http://proselint.com/'." + :command ("proselint" "--json" "-") + :standard-input t + :error-parser flycheck-proselint-parse-errors + :modes (text-mode markdown-mode gfm-mode message-mode org-mode)) + +(flycheck-def-option-var flycheck-protoc-import-path nil protobuf-protoc + "A list of directories to resolve import directives. + +The value of this variable is a list of strings, where each +string is a directory to add to the import path. Relative paths +are relative to the file being checked." + :type '(repeat (directory :tag "Import directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker protobuf-protoc + "A protobuf syntax checker using the protoc compiler. + +See URL `https://developers.google.com/protocol-buffers/'." + :command ("protoc" "--error_format" "gcc" + (eval (concat "--java_out=" (flycheck-temp-dir-system))) + ;; Add the current directory to resolve imports + (eval (concat "--proto_path=" + (file-name-directory (buffer-file-name)))) + ;; Add other import paths; this needs to be after the current + ;; directory to produce the right output. See URL + ;; `https://github.com/flycheck/flycheck/pull/1655' + (option-list "--proto_path=" flycheck-protoc-import-path concat) + source-inplace) + :error-patterns + ((info line-start (file-name) ":" line ":" column + ": note: " (message) line-end) + (error line-start (file-name) ":" line ":" column + ": " (message) line-end) + (error line-start + (message "In file included from") " " (file-name) ":" line ":" + column ":" line-end)) + :modes protobuf-mode + :predicate (lambda () (buffer-file-name))) + +(defun flycheck-prototool-project-root (&optional _checker) + "Return the nearest directory holding the prototool.yaml configuration." + (and buffer-file-name + (locate-dominating-file buffer-file-name "prototool.yaml"))) + +(flycheck-define-checker protobuf-prototool + "A protobuf syntax checker using prototool. + +See URL `https://github.com/uber/prototool'." + :command ("prototool" "lint" source-original) + :error-patterns + ((warning line-start (file-name) ":" line ":" column ":" (message) line-end)) + :modes protobuf-mode + :enabled flycheck-prototool-project-root + :predicate flycheck-buffer-saved-p) + +(flycheck-define-checker pug + "A Pug syntax checker using the pug compiler. + +See URL `https://pugjs.org/'." + :command ("pug" "-p" (eval (expand-file-name (buffer-file-name)))) + :standard-input t + :error-patterns + ;; errors with includes/extends (e.g. missing files) + ((error "Error: " (message) (zero-or-more not-newline) "\n" + (zero-or-more not-newline) "at " + (zero-or-more not-newline) " line " line) + ;; error when placing anything other than a mixin or + ;; block at the top-level of an extended template + ;; also unknown filters + (error line-start "Error: " (file-name) ":" + line ":" column "\n\n" (message) line-end) + ;; syntax/runtime errors (e.g. type errors, bad indentation, etc.) + (error line-start + (optional "Type") "Error: " (file-name) ":" + line (optional ":" column) + (zero-or-more not-newline) "\n" + (one-or-more (or (zero-or-more not-newline) "|" + (zero-or-more not-newline) "\n") + (zero-or-more "-") (zero-or-more not-newline) "|" + (zero-or-more not-newline) "\n") + (zero-or-more not-newline) "\n" + (one-or-more + (zero-or-more not-newline) "|" + (zero-or-more not-newline) "\n") + (zero-or-more not-newline) "\n" + (message) + line-end)) + :modes pug-mode) + +(flycheck-define-checker puppet-parser + "A Puppet DSL syntax checker using puppet's own parser. + +See URL `https://puppet.com/'." + :command ("puppet" "parser" "validate" "--color=false") + :standard-input t + :error-patterns + ( + ;; Patterns for Puppet 4 + (error line-start "Error: Could not parse for environment " + (one-or-more (in "a-z" "0-9" "_")) ":" + (message) "(line: " line ", column: " column ")" line-end) + ;; Errors from Puppet < 4 + (error line-start "Error: Could not parse for environment " + (one-or-more (in "a-z" "0-9" "_")) ":" + (message (minimal-match (one-or-more anything))) + " at line " line line-end) + (error line-start + ;; Skip over the path of the Puppet executable + (minimal-match (zero-or-more not-newline)) + ": Could not parse for environment " (one-or-more word) + ": " (message (minimal-match (zero-or-more anything))) + " at " (file-name "/" (zero-or-more not-newline)) ":" line line-end)) + :modes puppet-mode + :next-checkers ((warning . puppet-lint))) + +(flycheck-def-config-file-var flycheck-puppet-lint-rc puppet-lint + ".puppet-lint.rc" + :package-version '(flycheck . "26")) + +(flycheck-def-option-var flycheck-puppet-lint-disabled-checks nil puppet-lint + "Disabled checkers for `puppet-lint'. + +The value of this variable is a list of strings, where each +string is the name of a check to disable (e.g. \"80chars\" or +\"double_quoted_strings\"). + +See URL `http://puppet-lint.com/checks/' for a list of all checks +and their names." + :type '(repeat (string :tag "Check Name")) + :package-version '(flycheck . "26")) + +(defun flycheck-puppet-lint-disabled-arg-name (check) + "Create an argument to disable a puppetlint CHECK." + (concat "--no-" check "-check")) + +(flycheck-define-checker puppet-lint + "A Puppet DSL style checker using puppet-lint. + +See URL `http://puppet-lint.com/'." + ;; We must check the original file, because Puppetlint is quite picky on the + ;; names of files and there place in the directory structure, to comply with + ;; Puppet's autoload directory layout. For instance, a class foo::bar is + ;; required to be in a file foo/bar.pp. Any other place, such as a Flycheck + ;; temporary file will cause an error. + :command ("puppet-lint" + (config-file "--config" flycheck-puppet-lint-rc) + "--log-format" + "%{path}:%{line}:%{kind}: %{message} (%{check})" + (option-list "" flycheck-puppet-lint-disabled-checks concat + flycheck-puppet-lint-disabled-arg-name) + source-original) + :error-patterns + ((warning line-start (file-name) ":" line ":warning: " (message) line-end) + (error line-start (file-name) ":" line ":error: " (message) line-end)) + :modes puppet-mode + ;; Since we check the original file, we can only use this syntax checker if + ;; the buffer is actually linked to a file, and if it is not modified. + :predicate flycheck-buffer-saved-p) + +(defun flycheck-python-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") + +(flycheck-def-option-var flycheck-flake8-error-level-alist + '(("^E9.*$" . error) ; Syntax errors from pep8 + ("^F82.*$" . error) ; undefined variables from pyflakes + ("^F83.*$" . error) ; Duplicate arguments from flake8 + ("^D.*$" . info) ; Docstring issues from flake8-pep257 + ("^N.*$" . info) ; Naming issues from pep8-naming + ) + python-flake8 + "An alist mapping flake8 error IDs to Flycheck error levels. + +Each item in this list is a cons cell `(PATTERN . LEVEL)' where +PATTERN is a regular expression matched against the error ID, and +LEVEL is a Flycheck error level symbol. + +Each PATTERN is matched in the order of appearance in this list +against the error ID. If it matches the ID, the level of the +corresponding error is set to LEVEL. An error that is not +matched by any PATTERN defaults to warning level. + +The default value of this option matches errors from flake8 +itself and from the following flake8 plugins: + +- pep8-naming +- flake8-pep257 + +You may add your own mappings to this option in order to support +further flake8 plugins." + :type '(repeat (cons (regexp :tag "Error ID pattern") + (symbol :tag "Error level"))) + :package-version '(flycheck . "0.22")) + +(flycheck-def-option-var flycheck-flake8-maximum-complexity nil python-flake8 + "The maximum McCabe complexity of methods. + +If nil, do not check the complexity of methods. If set to an +integer, report any complexity greater than the value of this +variable as warning. + +If set to an integer, this variable overrules any similar setting +in the configuration file denoted by `flycheck-flake8rc'." + :type '(choice (const :tag "Do not check McCabe complexity" nil) + (integer :tag "Maximum complexity")) + :safe #'integerp) + +(flycheck-def-option-var flycheck-flake8-maximum-line-length nil python-flake8 + "The maximum length of lines. + +If set to an integer, the value of this variable denotes the +maximum length of lines, overruling any similar setting in the +configuration file denoted by `flycheck-flake8rc'. An error will +be reported for any line longer than the value of this variable. + +If set to nil, use the maximum line length from the configuration +file denoted by `flycheck-flake8rc', or the PEP 8 recommendation +of 79 characters if there is no configuration with this setting." + :type '(choice (const :tag "Default value") + (integer :tag "Maximum line length in characters")) + :safe #'integerp) + +(defun flycheck-flake8-fix-error-level (err) + "Fix the error level of ERR. + +Update the error level of ERR according to +`flycheck-flake8-error-level-alist'." + (pcase-dolist (`(,pattern . ,level) flycheck-flake8-error-level-alist) + (when (string-match-p pattern (flycheck-error-id err)) + (setf (flycheck-error-level err) level))) + err) + +(defun flycheck-flake8--find-project-root (_checker) + "Find setup.cfg in a parent directory of the current buffer." + ;; This is a workaround for `https://gitlab.com/pycqa/flake8/issues/517'; see + ;; also `https://github.com/flycheck/flycheck/issues/1722' + (locate-dominating-file (or buffer-file-name default-directory) "setup.cfg")) + +(flycheck-define-checker python-flake8 + "A Python syntax and style checker using Flake8. + +Requires Flake8 3.0 or newer. See URL +`https://flake8.readthedocs.io/'." + ;; Not calling flake8 directly makes it easier to switch between different + ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055. + :command ("python3" + (eval (flycheck-python-module-args 'python-flake8 "flake8")) + "--format=default" + (config-file "--append-config" flycheck-flake8rc) + (option "--max-complexity" flycheck-flake8-maximum-complexity nil + flycheck-option-int) + (option "--max-line-length" flycheck-flake8-maximum-line-length nil + flycheck-option-int) + (eval (when buffer-file-name + (concat "--stdin-display-name=" buffer-file-name))) + "-") + :standard-input t + :working-directory flycheck-flake8--find-project-root + :error-filter (lambda (errors) + (let ((errors (flycheck-sanitize-errors errors))) + (seq-map #'flycheck-flake8-fix-error-level errors))) + :error-patterns + ((warning line-start + (file-name) ":" line ":" (optional column ":") " " + (id (one-or-more (any alpha)) (one-or-more digit)) " " + (message (one-or-more not-newline)) + line-end)) + :enabled (lambda () + (or (not (flycheck-python-needs-module-p 'python-flake8)) + (flycheck-python-find-module 'python-flake8 "flake8"))) + :verify (lambda (_) (flycheck-python-verify-module 'python-flake8 "flake8")) + :modes python-mode + :next-checkers ((warning . python-pylint) + (warning . python-mypy))) + +(flycheck-def-config-file-var flycheck-pylintrc python-pylint ".pylintrc") + +(flycheck-def-option-var flycheck-pylint-use-symbolic-id t python-pylint + "Whether to use pylint message symbols or message codes. + +A pylint message has both an opaque identifying code (such as `F0401') and a +more meaningful symbolic code (such as `import-error'). This option governs +which should be used and reported to the user." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.25")) + +(defun flycheck-parse-pylint (output checker buffer) + "Parse JSON OUTPUT of CHECKER on BUFFER as Pylint errors." + (mapcar (lambda (err) + (let-alist err + ;; Pylint can return -1 as a line or a column, hence the call to + ;; `max'. See `https://github.com/flycheck/flycheck/issues/1383'. + (flycheck-error-new-at + (and .line (max .line 1)) + (and .column (max (1+ .column) 1)) + (pcase .type + ;; See "pylint/utils.py" + ((or "fatal" "error") 'error) + ((or "info" "convention") 'info) + ((or "warning" "refactor" _) 'warning)) + ;; Drop lines showing the error in context + (and (string-match (rx (*? nonl) eol) .message) + (match-string 0 .message)) + :id (if flycheck-pylint-use-symbolic-id .symbol .message-id) + :checker checker + :buffer buffer + :filename .path))) + (car (flycheck-parse-json output)))) + +(flycheck-define-checker python-pylint + "A Python syntax and style checker using Pylint. + +This syntax checker requires Pylint 1.0 or newer. + +See URL `https://www.pylint.org/'." + ;; --reports=n disables the scoring report. + ;; Not calling pylint directly makes it easier to switch between different + ;; Python versions; see https://github.com/flycheck/flycheck/issues/1055. + :command ("python3" + (eval (flycheck-python-module-args 'python-pylint "pylint")) + "--reports=n" + "--output-format=json" + (config-file "--rcfile=" flycheck-pylintrc concat) + ;; Need `source-inplace' for relative imports (e.g. `from .foo + ;; import bar'), see https://github.com/flycheck/flycheck/issues/280 + source-inplace) + :error-parser flycheck-parse-pylint + :enabled (lambda () + (or (not (flycheck-python-needs-module-p 'python-pylint)) + (flycheck-python-find-module 'python-pylint "pylint"))) + :verify (lambda (_) (flycheck-python-verify-module 'python-pylint "pylint")) + :modes python-mode + :next-checkers ((warning . python-mypy))) + +(flycheck-define-checker python-pycompile + "A Python syntax checker using Python's builtin compiler. + +See URL `https://docs.python.org/3.4/library/py_compile.html'." + :command ("python3" "-m" "py_compile" source) + :error-patterns + ;; Python 2.7 + ((error line-start " File \"" (file-name) "\", line " line "\n" + (>= 2 (zero-or-more not-newline) "\n") + "SyntaxError: " (message) line-end) + (error line-start "Sorry: IndentationError: " + (message) "(" (file-name) ", line " line ")" + line-end) + ;; 2.6 + (error line-start "SyntaxError: ('" (message (one-or-more (not (any "'")))) + "', ('" (file-name (one-or-more (not (any "'")))) "', " + line ", " column ", " (one-or-more not-newline) line-end)) + :modes python-mode + :next-checkers ((warning . python-mypy))) + +(define-obsolete-variable-alias 'flycheck-python-mypy-ini + 'flycheck-python-mypy-config "32") + +(flycheck-def-config-file-var flycheck-python-mypy-config python-mypy + '("mypy.ini" "setup.cfg")) + +(flycheck-def-option-var flycheck-python-mypy-cache-dir nil python-mypy + "Directory used to write .mypy_cache directories." + :type '(choice + (const :tag "Write to the working directory" nil) + (const :tag "Never write .mypy_cache directories" null-device) + (string :tag "Path")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) + +(flycheck-define-checker python-mypy + "Mypy syntax and type checker. Requires mypy>=0.580. + +See URL `http://mypy-lang.org/'." + :command ("mypy" + "--show-column-numbers" + (config-file "--config-file" flycheck-python-mypy-config) + (option "--cache-dir" flycheck-python-mypy-cache-dir) + source-original) + :error-patterns + ((error line-start (file-name) ":" line (optional ":" column) + ": error:" (message) line-end) + (warning line-start (file-name) ":" line (optional ":" column) + ": warning:" (message) line-end) + (info line-start (file-name) ":" line (optional ":" column) + ": note:" (message) line-end)) + :modes python-mode + ;; Ensure the file is saved, to work around + ;; https://github.com/python/mypy/issues/4746. + :predicate flycheck-buffer-saved-p) + +(flycheck-def-option-var flycheck-lintr-caching t r-lintr + "Whether to enable caching in lintr. + +By default, lintr caches all expressions in a file and re-checks +only those that have changed. Setting this option to nil +disables caching in case there are problems." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.23")) + +(flycheck-def-option-var flycheck-lintr-linters "default_linters" r-lintr + "Linters to use with lintr. + +The value of this variable is a string containing an R +expression, which selects linters for lintr." + :type 'string + :risky t + :package-version '(flycheck . "0.23")) + +(defun flycheck-r-has-lintr (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 + :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 + :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) + :end-line .pos.spanEnd.sourceLine + :end-column .pos.spanEnd.sourceColumn))) + (flycheck-parse-json output))) + +(flycheck-define-checker nix-linter + "Nix checker using nix-linter. + +See URL `https://github.com/Synthetica9/nix-linter'." + :command ("nix-linter" "--json-stream" "-") + :standard-input t + :error-parser flycheck-parse-nix-linter + :error-explainer + (lambda (error) + (-when-let (error-code (flycheck-error-id error)) + (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/'." + ;; include:: directives + :command ("rst2pseudoxml.py" "--report=2" "--halt=5" + ;; Read from standard input and throw output away + "-" null-device) + :standard-input t + :error-patterns + ((warning line-start ":" line ": (WARNING/2) " (message) line-end) + (error line-start ":" line + ": (" (or "ERROR/3" "SEVERE/4") ") " + (message) line-end)) + :modes rst-mode) + +(flycheck-def-option-var flycheck-sphinx-warn-on-missing-references t rst-sphinx + "Whether to warn about missing references in Sphinx. + +When non-nil (the default), warn about all missing references in +Sphinx via `-n'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.17")) + +(flycheck-define-checker rst-sphinx + "A ReStructuredText (RST) syntax checker using Sphinx. + +Requires Sphinx 1.2 or newer. See URL `http://sphinx-doc.org'." + :command ("sphinx-build" "-b" "pseudoxml" + "-q" "-N" ; Reduced output and no colors + (option-flag "-n" flycheck-sphinx-warn-on-missing-references) + (eval (flycheck-locate-sphinx-source-directory)) + temporary-directory ; Redirect the output to a temporary + ; directory + source-original) ; Sphinx needs the original document + :error-patterns + ((warning line-start (file-name) ":" line ": WARNING: " (message) line-end) + (error line-start + (file-name) ":" line + ": " (or "ERROR" "SEVERE") ": " + (message) line-end)) + :modes rst-mode + :predicate (lambda () (and (flycheck-buffer-saved-p) + (flycheck-locate-sphinx-source-directory)))) + +(defun flycheck-ruby--find-project-root (_checker) + "Compute an appropriate working-directory for flycheck-ruby. + +This is either a parent directory containing a Gemfile, or nil." + (and + buffer-file-name + (locate-dominating-file buffer-file-name "Gemfile"))) + +(flycheck-def-config-file-var flycheck-rubocoprc ruby-rubocop ".rubocop.yml") + +(flycheck-def-option-var flycheck-rubocop-lint-only nil + (ruby-rubocop ruby-standard) + "Whether to only report code issues in Rubocop and Standard. + +When non-nil, only report code issues, via `--lint'. Otherwise +report style issues as well." + :safe #'booleanp + :type 'boolean + :package-version '(flycheck . "0.16")) + +(defconst flycheck-ruby-rubocop-error-patterns + '((info line-start (file-name) ":" line ":" column ": C: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) line-end) + (warning line-start (file-name) ":" line ":" column ": W: " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end) + (error line-start (file-name) ":" line ":" column ": " (or "E" "F") ": " + (optional (id (one-or-more (not (any ":")))) ": ") (message) + line-end))) + +(flycheck-def-executable-var ruby-rubocop "rubocop") +(flycheck-define-command-checker 'ruby-rubocop + "A Ruby syntax and style checker using the RuboCop tool. + +You need at least RuboCop 0.34 for this syntax checker. + +See URL `http://batsov.com/rubocop/'." + ;; ruby-standard is defined based on this checker + :command '("rubocop" + "--display-cop-names" + "--force-exclusion" + "--format" "emacs" + ;; Explicitly disable caching to prevent Rubocop 0.35.1 and earlier + ;; from caching standard input. Later versions of Rubocop + ;; automatically disable caching with --stdin, see + ;; https://github.com/flycheck/flycheck/issues/844 and + ;; https://github.com/bbatsov/rubocop/issues/2576 + "--cache" "false" + (config-file "--config" flycheck-rubocoprc) + (option-flag "--lint" flycheck-rubocop-lint-only) + ;; Rubocop takes the original file name as argument when reading + ;; from standard input + "--stdin" source-original) + :standard-input t + :working-directory #'flycheck-ruby--find-project-root + :error-patterns flycheck-ruby-rubocop-error-patterns + :modes '(enh-ruby-mode ruby-mode) + :next-checkers '((warning . ruby-reek) + (warning . ruby-rubylint))) + +(flycheck-def-config-file-var flycheck-ruby-standardrc ruby-standard + ".standard.yml") + +(flycheck-def-executable-var ruby-standard "standardrb") +(flycheck-define-command-checker 'ruby-standard + "A Ruby syntax and style checker using the StandardRB gem. + +See URL `https://github.com/testdouble/standard' for more information." + ;; This checker is derived from ruby-rubocop; see above + :command '("standardrb" + "--display-cop-names" + "--force-exclusion" + "--format" "emacs" + "--cache" "false" + (config-file "--config" flycheck-ruby-standardrc) + (option-flag "--lint" flycheck-rubocop-lint-only) + "--stdin" source-original) + :standard-input t + :working-directory #'flycheck-ruby--find-project-root + :error-patterns flycheck-ruby-rubocop-error-patterns + :modes '(enh-ruby-mode ruby-mode) + :next-checkers '((warning . ruby-reek) + (warning . ruby-rubylint))) + +;; 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) + +(flycheck-define-checker ruby-rubylint + "A Ruby syntax and code analysis checker using ruby-lint. + +Requires ruby-lint 2.0.2 or newer. See URL +`https://github.com/YorickPeterse/ruby-lint'." + :command ("ruby-lint" "--presenter=syntastic" + (config-file "--config" flycheck-rubylintrc) + source) + ;; Ruby Lint can't read from standard input + :error-patterns + ((info line-start + (file-name) ":I:" line ":" column ": " (message) line-end) + (warning line-start + (file-name) ":W:" line ":" column ": " (message) line-end) + (error line-start + (file-name) ":E:" line ":" column ": " (message) line-end)) + :modes (enh-ruby-mode ruby-mode)) + +(flycheck-define-checker ruby + "A Ruby syntax checker using the standard Ruby interpreter. + +Please note that the output of different Ruby versions and +implementations varies wildly. This syntax checker supports +current versions of MRI and JRuby, but may break when used with +other implementations or future versions of these +implementations. + +Please consider using `ruby-rubocop' or `ruby-reek' instead. + +See URL `https://www.ruby-lang.org/'." + :command ("ruby" "-w" "-c") + :standard-input t + :error-patterns + ;; These patterns support output from JRuby, too, to deal with RVM or Rbenv + ((error line-start "SyntaxError in -:" line ": " (message) line-end) + (warning line-start "-:" line ":" (optional column ":") + " warning: " (message) line-end) + (error line-start "-:" line ": " (message) line-end)) + :modes (enh-ruby-mode ruby-mode) + :next-checkers ((warning . ruby-rubylint))) + +(flycheck-define-checker ruby-jruby + "A Ruby syntax checker using the JRuby interpreter. + +This syntax checker is very primitive, and may break on future +versions of JRuby. + +Please consider using `ruby-rubocop' or `ruby-rubylint' instead. + +See URL `http://jruby.org/'." + :command ("jruby" "-w" "-c") + :standard-input t + :error-patterns + ((error line-start "SyntaxError in -:" line ": " (message) line-end) + (warning line-start "-:" line ": warning: " (message) line-end) + (error line-start "-:" line ": " (message) line-end)) + :modes (enh-ruby-mode ruby-mode) + :next-checkers ((warning . ruby-rubylint))) + +(flycheck-def-args-var flycheck-cargo-check-args (rust-cargo) + :package-version '(flycheck . "32")) + +(flycheck-def-args-var flycheck-rust-args (rust) + :package-version '(flycheck . "0.24")) + +(flycheck-def-option-var flycheck-rust-check-tests t (rust-cargo rust) + "Whether to check test code in Rust. + +For the `rust' checker: When non-nil, `rustc' is passed the +`--test' flag, which will check any code marked with the +`#[cfg(test)]' attribute and any functions marked with +`#[test]'. Otherwise, `rustc' is not passed `--test' and test +code will not be checked. Skipping `--test' is necessary when +using `#![no_std]', because compiling the test runner requires +`std'. + +For the `rust-cargo' checker: When non-nil, calls `cargo test +--no-run' instead of `cargo check'." + :type 'boolean + :safe #'booleanp + :package-version '("flycheck" . "0.19")) + +(flycheck-def-option-var flycheck-rust-crate-root nil rust + "A path to the crate root for the current buffer. + +The value of this variable is either a string with the path to +the crate root for the current buffer, or nil if the current buffer +is a crate. A relative path is relative to the current buffer. + +If this variable is non nil the current buffer will only be checked +if it is not modified, i.e. after it has been saved." + :type '(choice (const :tag "Unspecified" nil) + (file :tag "Root")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "0.20")) +(make-variable-buffer-local 'flycheck-rust-crate-root) + +(flycheck-def-option-var flycheck-rust-crate-type "lib" (rust-cargo rust) + "The type of the Rust Crate to check. + +For `rust-cargo', the value should be a string denoting the +target type passed to Cargo. See +`flycheck-rust-valid-crate-type-p' for the list of allowed +values. + +For `rust', the value should be a string denoting the crate type +for the `--crate-type' flag of rustc." + :type '(choice (const :tag "nil (rust/rust-cargo)" nil) + (const :tag "lib (rust/rust-cargo)" "lib") + (const :tag "bin (rust/rust-cargo)" "bin") + (const :tag "example (rust-cargo)" "example") + (const :tag "test (rust-cargo)" "test") + (const :tag "bench (rust-cargo)" "bench") + (const :tag "rlib (rust)" "rlib") + (const :tag "dylib (rust)" "dylib") + (const :tag "cdylib (rust)" "cdylib") + (const :tag "staticlib (rust)" "staticlib") + (const :tag "metadata (rust)" "metadata")) + :safe #'stringp + :package-version '(flycheck . "0.20")) +(make-variable-buffer-local 'flycheck-rust-crate-type) + +(flycheck-def-option-var flycheck-rust-binary-name nil rust-cargo + "The name of the binary to pass to `cargo check --CRATE-TYPE'. + +The value of this variable is a string denoting the name of the +target to check: usually the name of the crate, or the name of +one of the files under `src/bin', `tests', `examples' or +`benches'. + +This always requires a non-nil value, unless +`flycheck-rust-crate-type' is `lib' or nil, in which case it is +ignored." + :type '(choice (const :tag "Unspecified" nil) + (string :tag "Binary name")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "28")) +(make-variable-buffer-local 'flycheck-rust-binary-name) + +(flycheck-def-option-var flycheck-rust-features nil rust-cargo + "List of features to activate during build or check. + +The value of this variable is a list of strings denoting features +that will be activated to build the target to check. Features will +be passed to `cargo check --features=FEATURES'." + :type '(repeat :tag "Features to activate" + (string :tag "Feature")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-rust-features) + +(flycheck-def-option-var flycheck-rust-library-path nil rust + "A list of library directories for Rust. + +The value of this variable is a list of strings, where each +string is a directory to add to the library path of Rust. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Library directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.18")) + +(defun flycheck-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" + :package-version '(flycheck . "30")) + +(flycheck-define-checker sass/scss-sass-lint + "A SASS/SCSS syntax checker using sass-Lint. + +See URL `https://github.com/sasstools/sass-lint'." + :command ("sass-lint" + "--verbose" + "--no-exit" + "--format" "Checkstyle" + (config-file "--config" flycheck-sass-lintrc) + source) + :error-parser flycheck-parse-checkstyle + :modes (sass-mode scss-mode)) + +(flycheck-define-checker scala + "A Scala syntax checker using the Scala compiler. + +See URL `https://www.scala-lang.org/'." + :command ("scalac" "-Ystop-after:parser" source) + :error-patterns + ((error line-start (file-name) ":" line ": error: " (message) line-end)) + :modes scala-mode + :next-checkers ((warning . scala-scalastyle))) + +(flycheck-def-config-file-var flycheck-scalastylerc scala-scalastyle nil + :package-version '(flycheck . "0.20")) + +(flycheck-define-checker scala-scalastyle + "A Scala style checker using scalastyle. + +Note that this syntax checker is not used if +`flycheck-scalastylerc' is nil or refers to a non-existing file. + +See URL `http://www.scalastyle.org'." + :command ("scalastyle" + (config-file "-c" flycheck-scalastylerc) + source) + :error-patterns + ((error line-start "error file=" (file-name) " message=" + (message) " line=" line (optional " column=" column) line-end) + (warning line-start "warning file=" (file-name) " message=" + (message) " line=" line (optional " column=" column) line-end)) + :error-filter (lambda (errors) + (flycheck-sanitize-errors + (flycheck-increment-error-columns errors))) + :modes scala-mode + :predicate + ;; Inhibit this syntax checker if the JAR or the configuration are unset or + ;; missing + (lambda () (and flycheck-scalastylerc + (flycheck-locate-config-file flycheck-scalastylerc + 'scala-scalastyle))) + :verify (lambda (checker) + (let ((config-file (and flycheck-scalastylerc + (flycheck-locate-config-file + flycheck-scalastylerc checker)))) + (list + (flycheck-verification-result-new + :label "Configuration file" + :message (cond + ((not flycheck-scalastylerc) + "`flycheck-scalastyletrc' not set") + ((not config-file) + (format "file %s not found" flycheck-scalastylerc)) + (t (format "found at %s" config-file))) + :face (cond + ((not flycheck-scalastylerc) '(bold warning)) + ((not config-file) '(bold error)) + (t 'success))))))) + +(flycheck-def-args-var flycheck-scheme-chicken-args scheme-chicken + :package-version '(flycheck . "32")) + +(flycheck-define-checker scheme-chicken + "A CHICKEN Scheme syntax checker using the CHICKEN compiler `csc'. + +See URL `http://call-cc.org/'." + :command ("csc" "-analyze-only" "-local" + (eval flycheck-scheme-chicken-args) + source) + :error-patterns + ((info line-start + "Note: " (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + (warning line-start + "Warning: " (zero-or-more not-newline) ",\n" + (one-or-more (any space)) (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + (warning line-start + "Warning: " (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + (error line-start "Error: (line " line ") " (message) line-end) + (error line-start "Syntax error: (" (file-name) ":" line ")" + (zero-or-more not-newline) " - " + (message (one-or-more not-newline) + (zero-or-more "\n" + (zero-or-more space) + (zero-or-more not-newline)) + (one-or-more space) "<--") + line-end) + ;; A of version 4.12.0, the chicken compiler doesn't provide a + ;; line number for this error. + (error line-start "Syntax error: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (zero-or-more space) + (zero-or-more not-newline)) + (one-or-more space) "<--") + line-end) + (error line-start + "Error: " (zero-or-more not-newline) ":\n" + (one-or-more (any space)) "(" (file-name) ":" line ") " (message) + line-end) + ;; A of version 4.12.0, the chicken compiler doesn't provide a + ;; line number for this error. + (error line-start "Error: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (zero-or-more space) + (zero-or-more not-newline)) + (one-or-more space) "<--"))) + :error-filter flycheck-fill-empty-line-numbers + :predicate + (lambda () + ;; In `scheme-mode' we must check the current Scheme implementation + ;; being used + (and (boundp 'geiser-impl--implementation) + (eq geiser-impl--implementation 'chicken))) + :verify + (lambda (_checker) + (let ((geiser-impl (bound-and-true-p geiser-impl--implementation))) + (list + (flycheck-verification-result-new + :label "Geiser Implementation" + :message (cond + ((eq geiser-impl 'chicken) "Chicken Scheme") + (geiser-impl (format "Other: %s" geiser-impl)) + (t "Geiser not active")) + :face (cond + ((eq geiser-impl 'chicken) 'success) + (t '(bold error))))))) + :modes scheme-mode) + +(defconst flycheck-scss-lint-checkstyle-re + (rx "cannot load such file" (1+ not-newline) "scss_lint_reporter_checkstyle") + "Regular expression to parse missing checkstyle error.") + +(defun flycheck-parse-scss-lint (output checker buffer) + "Parse SCSS-Lint OUTPUT from CHECKER and BUFFER. + +Like `flycheck-parse-checkstyle', but catches errors about +missing checkstyle reporter from SCSS-Lint." + (if (string-match-p flycheck-scss-lint-checkstyle-re output) + (list (flycheck-error-new-at + 1 nil 'error "Checkstyle reporter for SCSS-Lint missing. +Please run gem install scss_lint_reporter_checkstyle" + :checker checker + :buffer buffer + :filename (buffer-file-name buffer))) + (flycheck-parse-checkstyle output checker buffer))) + +(flycheck-def-config-file-var flycheck-scss-lintrc scss-lint ".scss-lint.yml" + :package-version '(flycheck . "0.23")) + +(flycheck-define-checker scss-lint + "A SCSS syntax checker using SCSS-Lint. + +Needs SCSS-Lint 0.43.2 or newer. + +See URL `https://github.com/brigade/scss-lint'." + :command ("scss-lint" + "--require=scss_lint_reporter_checkstyle" + "--format=Checkstyle" + (config-file "--config" flycheck-scss-lintrc) + "--stdin-file-path" source-original "-") + :standard-input t + ;; We cannot directly parse Checkstyle XML, since for some mysterious reason + ;; SCSS-Lint doesn't have a built-in Checkstyle reporter, and instead ships it + ;; as an addon which might not be installed. We use a custom error parser to + ;; check whether the addon is missing and turn that into a special kind of + ;; Flycheck error. + :error-parser flycheck-parse-scss-lint + :modes scss-mode + :verify + (lambda (checker) + (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 + :predicate flycheck-buffer-nonempty-p + :modes (scss-mode)) + +(flycheck-def-option-var flycheck-scss-compass nil scss + "Whether to enable the Compass CSS framework. + +When non-nil, enable the Compass CSS framework, via `--compass'." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "0.16")) + +(flycheck-define-checker scss + "A SCSS syntax checker using the SCSS compiler. + +See URL `http://sass-lang.com'." + :command ("scss" + "--cache-location" (eval (flycheck-sass-scss-cache-location)) + (option-flag "--compass" flycheck-scss-compass) + "--check" "--stdin") + :standard-input t + :error-patterns + ((error line-start + (or "Syntax error: " "Error: ") + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + (optional "\r") "\n" (one-or-more " ") "on line " line + " of standard input" + line-end) + (warning line-start + "WARNING: " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + (optional "\r") "\n" (one-or-more " ") "on line " line + " of an unknown file" + line-end)) + :modes scss-mode) + +(flycheck-def-args-var flycheck-sh-bash-args (sh-bash) + :package-version '(flycheck . "32")) + +(flycheck-define-checker sh-bash + "A Bash syntax checker using the Bash shell. + +See URL `http://www.gnu.org/software/bash/'." + :command ("bash" "--norc" "-n" + (eval flycheck-sh-bash-args) + "--") + :standard-input t + :error-patterns + ((error line-start + ;; The name/path of the bash executable + (one-or-more (not (any ":"))) ":" + ;; A label "line", possibly localized + (one-or-more (not (any digit))) + line (zero-or-more " ") ":" (zero-or-more " ") + (message) line-end)) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'bash)) + :next-checkers ((warning . sh-shellcheck))) + +(flycheck-define-checker sh-posix-dash + "A POSIX Shell syntax checker using the Dash shell. + +See URL `http://gondor.apana.org.au/~herbert/dash/'." + :command ("dash" "-n") + :standard-input t + :error-patterns + ((error line-start (one-or-more (not (any ":"))) ": " line ": " (message))) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'sh)) + :next-checkers ((warning . sh-shellcheck))) + +(flycheck-define-checker sh-posix-bash + "A POSIX Shell syntax checker using the Bash shell. + +See URL `http://www.gnu.org/software/bash/'." + :command ("bash" "--posix" "--norc" "-n" "--") + :standard-input t + :error-patterns + ((error line-start + ;; The name/path of the bash executable + (one-or-more (not (any ":"))) ":" + ;; A label "line", possibly localized + (one-or-more (not (any digit))) + line (zero-or-more " ") ":" (zero-or-more " ") + (message) line-end)) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'sh)) + :next-checkers ((warning . sh-shellcheck))) + +(flycheck-define-checker sh-zsh + "A Zsh syntax checker using the Zsh shell. + +See URL `http://www.zsh.org/'." + :command ("zsh" "--no-exec" "--no-globalrcs" "--no-rcs" source) + :error-patterns + ((error line-start (file-name) ":" line ": " (message) line-end)) + :modes sh-mode + :predicate (lambda () (eq sh-shell 'zsh)) + :next-checkers ((warning . sh-shellcheck))) + +(defconst flycheck-shellcheck-supported-shells '(bash ksh88 sh) + "Shells supported by ShellCheck.") + +(flycheck-def-option-var flycheck-shellcheck-excluded-warnings nil sh-shellcheck + "A list of excluded warnings for ShellCheck. + +The value of this variable is a list of strings, where each +string is a warning code to be excluded from ShellCheck reports. +By default, no warnings are excluded." + :type '(repeat :tag "Excluded warnings" + (string :tag "Warning code")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.21")) + +(flycheck-def-option-var flycheck-shellcheck-follow-sources t sh-shellcheck + "Whether to follow external sourced files in scripts. + +Shellcheck will follow and parse sourced files so long as a +pre-runtime resolvable path to the file is present. This can +either be part of the source command itself: + source /full/path/to/file.txt +or added as a shellcheck directive before the source command: + # shellcheck source=/full/path/to/file.txt." + :type 'boolean + :safe #'booleanp + :package-version '(flycheck . "31")) + +(flycheck-define-checker sh-shellcheck + "A shell script syntax and style checker using Shellcheck. + +See URL `https://github.com/koalaman/shellcheck/'." + :command ("shellcheck" + "--format" "checkstyle" + "--shell" (eval (symbol-name sh-shell)) + (option-flag "--external-sources" + flycheck-shellcheck-follow-sources) + (option "--exclude" flycheck-shellcheck-excluded-warnings list + flycheck-option-comma-separated-list) + "-") + :standard-input t + :error-parser flycheck-parse-checkstyle + :error-filter + (lambda (errors) + (flycheck-remove-error-file-names + "-" (flycheck-dequalify-error-ids errors))) + :modes sh-mode + :predicate (lambda () (memq sh-shell flycheck-shellcheck-supported-shells)) + :verify (lambda (_) + (let ((supports-shell (memq sh-shell + flycheck-shellcheck-supported-shells))) + (list + (flycheck-verification-result-new + :label (format "Shell %s supported" sh-shell) + :message (if supports-shell "yes" "no") + :face (if supports-shell 'success '(bold warning))))))) + +(flycheck-define-checker slim + "A Slim syntax checker using the Slim compiler. + +See URL `http://slim-lang.com'." + :command ("slimrb" "--compile") + :standard-input t + :error-patterns + ((error line-start + "Slim::Parser::SyntaxError:" (message) (optional "\r") "\n " + "STDIN, Line " line (optional ", Column " column) + line-end)) + :modes slim-mode + :next-checkers ((warning . slim-lint))) + +(flycheck-define-checker slim-lint + "A Slim linter. + +See URL `https://github.com/sds/slim-lint'." + :command ("slim-lint" "--reporter=checkstyle" source) + :error-parser flycheck-parse-checkstyle + :modes slim-mode) + +(flycheck-define-checker sql-sqlint + "A SQL syntax checker using the sqlint tool. + +See URL `https://github.com/purcell/sqlint'." + :command ("sqlint") + :standard-input t + :error-patterns + ((warning line-start "stdin:" line ":" column ":WARNING " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + line-end) + (error line-start "stdin:" line ":" column ":ERROR " + (message (one-or-more not-newline) + (zero-or-more "\n" + (one-or-more " ") + (one-or-more not-newline))) + line-end)) + :modes (sql-mode)) + +(flycheck-define-checker systemd-analyze + "A systemd unit checker using systemd-analyze(1). + +See URL +`https://www.freedesktop.org/software/systemd/man/systemd-analyze.html'." + :command ("systemd-analyze" "verify" source) + :error-parser flycheck-parse-with-patterns-without-color + :error-patterns + ((error line-start (file-name) ":" (optional line ":") (message) line-end) + (error line-start "[" (file-name) ":" line "]" (message) line-end)) + :error-filter flycheck-fill-empty-line-numbers + :modes (systemd-mode)) + +(flycheck-def-config-file-var flycheck-chktexrc tex-chktex ".chktexrc") + +(flycheck-define-checker tcl-nagelfar + "An extensible tcl syntax checker + +See URL `http://nagelfar.sourceforge.net/'." + :command ("nagelfar" "-H" source) + :error-patterns + ;; foo.tcl: 29: E Wrong number of arguments (4) to "set" + ;; foo.tcl: 29: W Expr without braces + ((info line-start (file-name) ": " line ": N " (message) line-end) + (warning line-start (file-name) ": " line ": W " (message) line-end) + (error line-start (file-name) ": " line ": E " (message) line-end)) + :modes tcl-mode) + +(flycheck-define-checker terraform + "A Terraform syntax checker with `terraform fmt'. + +See URL `https://www.terraform.io/docs/commands/fmt.html'." + :command ("terraform" "fmt" "-no-color" "-") + :standard-input t + :error-patterns + ((error line-start "Error: " (one-or-more not-newline) + "\n\n on line " line ":\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) + (_ '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") + +;; This needs to be set because textlint plugins are installed separately, +;; and there is no way to check their installation status -- textlint simply +;; prints a backtrace. +(flycheck-def-option-var flycheck-textlint-plugin-alist + '((markdown-mode . "@textlint/markdown") + (gfm-mode . "@textlint/markdown") + (t . "@textlint/text")) + textlint + "An alist mapping major modes to textlint plugins. + +Each item is a cons cell `(MAJOR-MODE . PLUGIN)', where MAJOR-MODE is a mode +`flycheck-textlint' supports and PLUGIN is a textlint plugin. As a catch-all, +when MAJOR-MODE is t, that PLUGIN will be used for any supported mode that +isn't specified. + +See URL `https://npms.io/search?q=textlint-plugin' for all textlint plugins +published on NPM." + :type '(repeat (choice (cons symbol string) + (cons (const t) string)))) + +(defun flycheck--textlint-get-plugin () + "Return the textlint plugin for the current mode." + (cdr (-first + (lambda (arg) + (pcase-let ((`(,mode . _) arg)) + (or (and (booleanp mode) mode) ; mode is t + (derived-mode-p mode)))) + flycheck-textlint-plugin-alist))) + +(flycheck-define-checker textlint + "A text prose linter using textlint. + +See URL `https://textlint.github.io/'." + :command ("textlint" + (config-file "--config" flycheck-textlint-config) + "--format" "json" + ;; get the first matching plugin from plugin-alist + "--plugin" + (eval (flycheck--textlint-get-plugin)) + source) + ;; textlint seems to say that its json output is compatible with ESLint. + ;; https://textlint.github.io/docs/formatter.html + :error-parser flycheck-parse-eslint + ;; textlint can support different formats with textlint plugins, but + ;; only text and markdown formats are installed by default. Ask the + ;; user to add mode->plugin mappings manually in + ;; `flycheck-textlint-plugin-alist'. + :modes + (text-mode markdown-mode gfm-mode message-mode adoc-mode + mhtml-mode latex-mode org-mode rst-mode) + :enabled + (lambda () (flycheck--textlint-get-plugin)) + :verify + (lambda (_) + (let ((plugin (flycheck--textlint-get-plugin))) + (list + (flycheck-verification-result-new + :label "textlint plugin" + :message plugin + :face 'success))))) + +(flycheck-def-config-file-var flycheck-typescript-tslint-config + typescript-tslint "tslint.json" + :package-version '(flycheck . "27")) + +(flycheck-def-option-var flycheck-typescript-tslint-rulesdir + nil typescript-tslint + "The directory of custom rules for TSLint. + +The value of this variable is either a string containing the path +to a directory with custom rules, or nil, to not give any custom +rules to TSLint. + +Refer to the TSLint manual at URL +`http://palantir.github.io/tslint/usage/cli/' +for more information about the custom directory." + :type '(choice (const :tag "No custom rules directory" nil) + (directory :tag "Custom rules directory")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "27")) + +(flycheck-def-args-var flycheck-tslint-args (typescript-tslint) + :package-version '(flycheck . "31")) + +(flycheck-define-checker typescript-tslint + "TypeScript style checker using TSLint. + +Note that this syntax checker is not used if +`flycheck-typescript-tslint-config' is nil or refers to a +non-existing file. + +See URL `https://github.com/palantir/tslint'." + :command ("tslint" "--format" "json" + (config-file "--config" flycheck-typescript-tslint-config) + (option "--rules-dir" flycheck-typescript-tslint-rulesdir) + (eval flycheck-tslint-args) + source-inplace) + :error-parser flycheck-parse-tslint + :modes (typescript-mode)) + +(flycheck-def-option-var flycheck-verilator-include-path nil verilog-verilator + "A list of include directories for Verilator. + +The value of this variable is a list of strings, where each +string is a directory to add to the include path of Verilator. +Relative paths are relative to the file being checked." + :type '(repeat (directory :tag "Include directory")) + :safe #'flycheck-string-list-p + :package-version '(flycheck . "0.24")) + +(flycheck-define-checker verilog-verilator + "A Verilog syntax checker using the Verilator Verilog HDL simulator. + +See URL `https://www.veripool.org/wiki/verilator'." + :command ("verilator" "--lint-only" "-Wall" + (option-list "-I" flycheck-verilator-include-path concat) + source) + :error-patterns + ((warning line-start "%Warning-" (zero-or-more not-newline) ": " + (file-name) ":" line ": " (message) line-end) + (error line-start "%Error: " (file-name) ":" + line ": " (message) line-end)) + :modes verilog-mode) + +(flycheck-def-option-var flycheck-ghdl-language-standard nil vhdl-ghdl + "The language standard to use in GHDL. + +The value of this variable is either a string denoting a language +standard, or nil, to use the default standard. When non-nil, +pass the language standard via the `--std' option." + :type '(choice (const :tag "Default standard" nil) + (string :tag "Language standard")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-ghdl-language-standard) + +(flycheck-def-option-var flycheck-ghdl-workdir nil vhdl-ghdl + "The directory to use for the file library. + +The value of this variable is either a string with the directory +to use for the file library, or nil, to use the default value. +When non-nil, pass the directory via the `--workdir' option." + :type '(choice (const :tag "Default directory" nil) + (string :tag "Directory for the file library")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-ghdl-workdir) + +(flycheck-def-option-var flycheck-ghdl-ieee-library nil vhdl-ghdl + "The standard to use for the IEEE library. + +The value of this variable is either a string denoting an ieee library +standard, or nil, to use the default standard. When non-nil, +pass the ieee library standard via the `--ieee' option." + :type '(choice (const :tag "Default standard" nil) + (const :tag "No IEEE Library" "none") + (const :tag "IEEE standard" "standard") + (const :tag "Synopsys standard" "synopsys") + (const :tag "Mentor standard" "mentor")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "32")) +(make-variable-buffer-local 'flycheck-ghdl-ieee-library) + +(flycheck-define-checker vhdl-ghdl + "A VHDL syntax checker using GHDL. + +See URL `https://github.com/ghdl/ghdl'." + :command ("ghdl" + "-s" ; only do the syntax checking + (option "--std=" flycheck-ghdl-language-standard concat) + (option "--workdir=" flycheck-ghdl-workdir concat) + (option "--ieee=" flycheck-ghdl-ieee-library concat) + source) + :error-patterns + ((error line-start (file-name) ":" line ":" column ": " (message) line-end)) + :modes vhdl-mode) + +(flycheck-def-option-var flycheck-xml-xmlstarlet-xsd-path nil xml-xmlstarlet + "An XSD schema to validate against." + :type '(choice (const :tag "None" nil) + (file :tag "XSD schema")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "31")) + +(flycheck-define-checker xml-xmlstarlet + "A XML syntax checker and validator using the xmlstarlet utility. + +See URL `http://xmlstar.sourceforge.net/'." + ;; Validate standard input with verbose error messages, and do not dump + ;; contents to standard output + :command ("xmlstarlet" "val" "--err" "--quiet" + (option "--xsd" flycheck-xml-xmlstarlet-xsd-path) + "-") + :standard-input t + :error-patterns + ((error line-start "-:" line "." column ": " (message) line-end)) + :modes (xml-mode nxml-mode)) + +(flycheck-def-option-var flycheck-xml-xmllint-xsd-path nil xml-xmllint + "An XSD schema to validate against." + :type '(choice (const :tag "None" nil) + (file :tag "XSD schema")) + :safe #'flycheck-string-or-nil-p + :package-version '(flycheck . "31")) + +(flycheck-define-checker xml-xmllint + "A XML syntax checker and validator using the xmllint utility. + +The xmllint is part of libxml2, see URL +`http://www.xmlsoft.org/'." + :command ("xmllint" "--noout" + (option "--schema" flycheck-xml-xmllint-xsd-path) + "-") + :standard-input t + :error-patterns + ((error line-start "-:" line ": " (message) line-end)) + :modes (xml-mode nxml-mode)) + +(flycheck-define-checker yaml-jsyaml + "A YAML syntax checker using JS-YAML. + +See URL `https://github.com/nodeca/js-yaml'." + :command ("js-yaml") + :standard-input t + :error-patterns + ((error line-start + (or "JS-YAML" "YAMLException") ": " + (message) " at line " line ", column " column ":" + line-end)) + :modes yaml-mode + :next-checkers ((warning . cwl))) + +(flycheck-define-checker yaml-ruby + "A YAML syntax checker using Ruby's YAML parser. + +This syntax checker uses the YAML parser from Ruby's standard +library. + +See URL `http://www.ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html'." + :command ("ruby" "-ryaml" "-e" "begin; + YAML.load(STDIN); \ + rescue Exception => e; \ + STDERR.puts \"stdin:#{e}\"; \ + end") + :standard-input t + :error-patterns + ((error line-start "stdin:" (zero-or-more not-newline) ":" (message) + "at line " line " column " column line-end)) + :modes yaml-mode + :next-checkers ((warning . cwl))) + +(flycheck-def-config-file-var flycheck-yamllintrc yaml-yamllint ".yamllint") + +(flycheck-define-checker yaml-yamllint + "A YAML syntax checker using YAMLLint. +See URL `https://github.com/adrienverge/yamllint'." + :standard-input t + :command ("yamllint" "-f" "parsable" "-" + (config-file "-c" flycheck-yamllintrc)) + :error-patterns + ((error line-start + "stdin:" line ":" column ": [error] " (message) line-end) + (warning line-start + "stdin:" line ":" column ": [warning] " (message) line-end)) + :modes yaml-mode) + +(provide 'flycheck) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: + +;;; flycheck.el ends here diff --git a/elpa/flycheck-20200405.2310/flycheck.elc b/elpa/flycheck-20200405.2310/flycheck.elc new file mode 100644 index 0000000000000000000000000000000000000000..2fe9a200e68416daf3dfdd5686dfe7609211b7fc GIT binary patch literal 526885 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 LDNIrA%NPHDG^!Zx literal 0 HcmV?d00001