flycheck.el 105 KB
Newer Older
1
;;; flycheck.el --- On-the-fly syntax checking (Flymake done right) -*- lexical-binding: t; -*-
Sebastian Wiesner's avatar
Sebastian Wiesner committed
2

Sebastian Wiesner's avatar
Sebastian Wiesner committed
3
;; Copyright (c) 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
Sebastian Wiesner's avatar
Sebastian Wiesner committed
4 5
;;
;; Author: Sebastian Wiesner <lunaryorn@gmail.com>
6
;; URL: https://github.com/lunaryorn/flycheck
Sebastian Wiesner's avatar
Sebastian Wiesner committed
7
;; Keywords: convenience languages tools
Sebastian Wiesner's avatar
Sebastian Wiesner committed
8
;; Version: 0.10
9
;; Package-Requires: ((s "1.3.1") (dash "1.2") (cl-lib "0.1") (emacs "24.1"))
Sebastian Wiesner's avatar
Sebastian Wiesner committed
10 11 12

;; This file is not part of GNU Emacs.

Sebastian Wiesner's avatar
Sebastian Wiesner committed
13 14 15 16 17 18 19 20 21 22 23 24
;; 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 <http://www.gnu.org/licenses/>.
Sebastian Wiesner's avatar
Sebastian Wiesner committed
25 26 27

;;; Commentary:

28
;; Modern on-the-fly syntax checking for GNU Emacs (aka "flymake done right")
29

30 31 32 33 34
;; Provide `flycheck-mode' which enables on-the-fly syntax checking for a large
;; number of different modes and languages (see `flycheck-checkers' for a
;; complete list).
;;
;; Support for new modes and languages can be added by declaring a new syntax
35
;; checker (see `flycheck-declare-checker').
Sebastian Wiesner's avatar
Sebastian Wiesner committed
36 37 38

;;; Code:

39
(eval-when-compile
Sebastian Wiesner's avatar
Sebastian Wiesner committed
40
  ;; For JKA workarounds in `flycheck-temp-file-system'
41
  (require 'jka-compr)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
42 43
  ;; For integration into Compile Mode
  (require 'compile))
44

45
(require 'cl-lib)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
46
(require 's)
47
(require 'dash)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
48

Sebastian Wiesner's avatar
Sebastian Wiesner committed
49

50
;;;; Compatibility
51
(eval-and-compile
52 53 54 55 56 57 58 59 60 61 62
  (unless (and (fboundp 'defvar-local)
               (eq (car (symbol-function 'defvar-local)) 'macro))
    (defmacro defvar-local (var val &optional docstring)
      "Define VAR as a buffer-local variable with default value VAL.
Like `defvar' but additionally marks the variable as being automatically
buffer-local wherever it is set."
      (declare (debug defvar) (doc-string 3))
      ;; Can't use backquote here, it's too early in the bootstrap.
      (list 'progn (list 'defvar var val docstring)
            (list 'make-variable-buffer-local (list 'quote var))))))

63 64 65 66 67 68 69 70 71
(eval-and-compile
  (unless (fboundp 'user-error)
    ;; Provide `user-error' for Emacs 24.2
    (defalias 'user-error 'error)
    ;; And make the debugger ignore our Flycheck user errors in Emacs 24.2
    (add-to-list 'debug-ignored-errors "\\`No more Flycheck errors\\'")
    (add-to-list 'debug-ignored-errors "\\`Flycheck mode disabled\\'")
    (add-to-list 'debug-ignored-errors
                 "\\`Configured syntax checker .* cannot be used\\'")))
72

Sebastian Wiesner's avatar
Sebastian Wiesner committed
73

74
;;;; Customization
75
(defgroup flycheck nil
Sebastian Wiesner's avatar
Sebastian Wiesner committed
76
  "On-the-fly syntax checking (aka \"flymake done right\")."
77 78 79 80
  :prefix "flycheck-"
  :group 'tools)

(defgroup flycheck-config-files nil
81 82 83 84 85 86
  "Configuration files for on-the-fly syntax checkers."
  :prefix "flycheck-"
  :group 'flycheck)

(defgroup flycheck-options nil
  "Options for on-the-fly syntax checkers."
87 88 89
  :prefix "flycheck-"
  :group 'flycheck)

90 91 92 93 94
(defgroup flycheck-faces nil
  "Faces used by on-the-fly syntax checking."
  :prefix "flycheck-"
  :group 'flycheck)

95 96
(defcustom flycheck-checkers
  '(bash
97 98
    coffee-coffeelint
    css-csslint
99
    elixir
100
    emacs-lisp
101
    emacs-lisp-checkdoc
102
    erlang
103
    go-gofmt
104 105
    go-build
    go-test
106
    haml
107
    html-tidy
108
    javascript-jshint
109
    json-jsonlint
110 111 112
    lua
    perl
    php
113
    php-phpcs
114 115
    python-flake8
    python-pylint
116
    rst
117
    ruby-rubocop
118
    ruby
119
    rust
120
    sass
121
    scala
122
    scss
123 124
    sh-dash
    sh-bash
125 126 127 128
    tex-chktex
    tex-lacheck
    xml-xmlstarlet
    zsh)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
129
  "Syntax checkers available for automatic selection.
130

Sebastian Wiesner's avatar
Sebastian Wiesner committed
131 132 133 134
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'.
135

Sebastian Wiesner's avatar
Sebastian Wiesner committed
136 137
Syntax checkers in this list must be declared with
`flycheck-declare-checker'."
138 139 140 141
  :group 'flycheck
  :type '(repeat (symbol :tag "Checker")))

(defvar-local flycheck-checker nil
Sebastian Wiesner's avatar
Sebastian Wiesner committed
142
  "Syntax checker to use for the current buffer.
143

Sebastian Wiesner's avatar
Sebastian Wiesner committed
144 145
If unset or nil, automatically select a suitable syntax checker
from `flycheck-checkers' on every syntax check.
146

Sebastian Wiesner's avatar
Sebastian Wiesner committed
147 148
If set to a syntax checker only use this syntax checker and never
select one from `flycheck-checkers' automatically.  If the syntax
149 150
checker is unusable in the current buffer an error is signaled.

Sebastian Wiesner's avatar
Sebastian Wiesner committed
151
A syntax checker assigned to this variable must be declared with
152 153
`flycheck-declare-checker'.

Sebastian Wiesner's avatar
Sebastian Wiesner committed
154 155 156 157
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.")
158 159 160 161
(put 'flycheck-checker 'safe-local-variable 'flycheck-registered-checker-p)

(defface flycheck-error-face
  '((t :inherit error))
162 163
  "Face for on-the-fly syntax checking errors."
  :group 'flycheck-faces)
164 165 166

(defface flycheck-warning-face
  '((t :inherit warning))
167 168
  "Face for on-the-fly syntax checking warnings."
  :group 'flycheck-faces)
169

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
(defcustom flycheck-indication-mode 'left-fringe
  "The indication mode for Flycheck errors and warnings.

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, errors and warnings are not indicated.  However,
they may still be highlighted 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)))

187
(defcustom flycheck-highlighting-mode 'columns
Sebastian Wiesner's avatar
Sebastian Wiesner committed
188
  "The highlighting mode for Flycheck errors and warnings.
189 190

Controls how Flycheck highlights errors in buffers.  May either
191
be `columns', `lines' or nil.
192

193 194 195 196 197
If set to `columns' highlight specific columns if errors are
specific to a column.  If set to `lines' always highlight the
whole line regardless of whether the error is specific to a
column.  If nil do no highlight errors at all, but only show
fringe icons.
198 199 200 201 202 203 204 205 206 207

Note that this does not affect error navigation.  When navigating
errors with `next-error' and `previous-error' Flycheck always
jumps to the error column regardless of the highlighting mode."
  :group 'flycheck
  :type '(choice (const :tag "Highlight columns only" columns)
                 (const :tag "Highlight whole lines" lines)
                 (const :tag "Do not highlight errors" nil))
  :package-version '(flycheck . "0.6"))

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
(defcustom flycheck-check-syntax-automatically '(save 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:

`mode-enabled' checks syntax automatically when `flycheck-mode'
is enabled.

`save' checks syntax automatically each time the buffer is saved.

`new-line' checks syntax automatically each time a new line is
inserted into the buffer.

For instance, set this variable to '(mode-enabled save) to only
check syntax automatically when saving a buffer, but never when
modifying its contents.

If nil, never check syntax automatically.  Use `flycheck-buffer'
to start a syntax check manually."
  :group 'flycheck
  :type '(set (const :tag "After the buffer was saved" save)
              (const :tag "After a new line was inserted" new-line)
              (const :tag "After `flycheck-mode' was enabled" mode-enabled))
  :package-version '(flycheck . "0.11"))

234 235 236 237 238 239 240 241 242 243 244 245 246 247
(defcustom flycheck-mode-hook nil
  "Hooks to run after `flycheck-mode'."
  :group 'flycheck
  :type 'hook)

(defcustom flycheck-after-syntax-check-hook nil
  "Hooks to run after each syntax check.

This hook is run after the syntax check process finished, all
error messages were parsed and properly reported (including
overlay setup)."
  :group 'flycheck
  :type 'hook)

Sebastian Wiesner's avatar
Sebastian Wiesner committed
248

249
;;;; Minor mode definition
250 251 252 253 254 255 256
;;;###autoload
(defconst flycheck-mode-line-lighter " FlyC"
  "The standard lighter for flycheck mode.")

(defvar-local flycheck-mode-line nil
  "The mode line lighter of variable `flycheck-mode'.")

257 258 259 260 261
(defvar flycheck-mode-map
  (let ((map (make-sparse-keymap))
        (pmap (make-sparse-keymap)))
    (define-key pmap "c" 'flycheck-buffer)
    (define-key pmap "C" 'flycheck-clear)
262
    (define-key pmap (kbd "C-c") 'flycheck-compile)
263 264
    (define-key pmap "n" 'flycheck-next-error)
    (define-key pmap "p" 'flycheck-previous-error)
265
    (define-key pmap (kbd "C-w") 'flycheck-copy-messages-as-kill)
266
    (define-key pmap "/" 'flycheck-google-messages)
267 268
    (define-key pmap "s" 'flycheck-select-checker)
    (define-key pmap "?" 'flycheck-describe-checker)
269
    (define-key pmap "i" 'flycheck-info)
270 271 272 273
    (define-key map (kbd "C-c !") pmap)
    map)
  "Keymap of `flycheck-mode'.")

Sebastian Wiesner's avatar
Sebastian Wiesner committed
274 275 276 277
(easy-menu-change
 '("Tools") "Syntax Checking"
 '(["Check current buffer" flycheck-buffer t]
   ["Clear errors in buffer" flycheck-clear t]
278
   ["Compile current buffer" flycheck-compile t]
Sebastian Wiesner's avatar
Sebastian Wiesner committed
279
   "---"
280 281
   ["Go to next error" flycheck-next-error t]
   ["Go to next error" flycheck-previous-error t]
282
   ["Google messages at point" flycheck-google-messages t]
283
   "---"
284
   ["Select syntax checker" flycheck-select-checker t]
Sebastian Wiesner's avatar
Sebastian Wiesner committed
285
   "---"
286 287
   ["Describe syntax checker" flycheck-describe-checker t]
   ["Read the Flycheck manual" flycheck-info t])
288
 "Spell Checking")
289

Sebastian Wiesner's avatar
Sebastian Wiesner committed
290
(easy-menu-change '("Tools") "--" nil "Spell Checking")
291

292 293 294 295 296
(defun flycheck-teardown ()
  "Teardown flyheck.

Completely clear the whole flycheck state.  Remove overlays, kill
running checks, and empty all variables used by flycheck."
297
  (flycheck-clean-deferred-check)
298 299
  (flycheck-clear)
  (flycheck-stop-checker)
300
  (flycheck-cancel-error-show-error-timer)
301
  (flycheck-safe-delete-temporaries)
302 303
  (flycheck-clear-checker))

304 305 306
(defvar-local flycheck-previous-next-error-function nil
  "Remember the previous `next-error-function'.")

307
(defconst flycheck-hooks-alist
308
  '(
309 310
    ;; Handle events that may start automatic syntax checks
    (after-save-hook                  . flycheck-handle-save)
311
    (after-change-functions           . flycheck-handle-change)
312 313 314
    ;; Handle events that may triggered pending deferred checks
    (window-configuration-change-hook . flycheck-perform-deferred-syntax-check)
    ;; Tear down Flycheck if the buffer or Emacs is kill
315
    (kill-buffer-hook                 . flycheck-teardown)
316
    (kill-emacs-hook                  . flycheck-teardown)
317
    ;; Show or hide error popups after commands
318 319
    (post-command-hook                . flycheck-show-error-at-point-soon)
    (post-command-hook                . flycheck-hide-error-buffer)
320
    ;; Immediately show error popups when navigating to an error
321 322 323 324 325 326 327
    (next-error-hook                  . flycheck-show-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.")

328 329 330 331 332 333 334 335 336 337
;;;###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'.
338 339 340
Otherwise behave as if called interactively.

In `flycheck-mode' the buffer is automatically syntax-checked
Sebastian Wiesner's avatar
Sebastian Wiesner committed
341 342
using the first suitable syntax checker from `flycheck-checkers'.
Use `flycheck-select-checker' to select a checker for the current
343 344 345
buffer manually.

\\{flycheck-mode-map}"
346
  :init-value nil
347
  :keymap flycheck-mode-map
348
  :lighter flycheck-mode-line
349
  :group 'flycheck
350 351 352
  :require 'flycheck
  (cond
   (flycheck-mode
353
    (flycheck-clear)
354

355 356
    (--each flycheck-hooks-alist
      (add-hook (car it) (cdr it) nil t))
357 358 359 360

    (setq flycheck-previous-next-error-function next-error-function)
    (setq next-error-function 'flycheck-next-error-function)

361
    (flycheck-buffer-automatically 'mode-enabled))
362
   (t
363
    (setq next-error-function flycheck-previous-next-error-function)
364

365 366 367
    (--each flycheck-hooks-alist
      (remove-hook (car it) (cdr it) t))

368 369
    (flycheck-teardown))))

370 371

;;; Global syntax checking
372 373 374 375
(defun flycheck-may-enable-mode ()
  "Determine whether Flycheck mode may be enabled.

Flycheck mode is not enabled under any of the following
376
conditions
377

378 379 380
The current buffer is a temporary buffer as determined by
`flycheck-temporary-buffer-p'.

381 382
The current buffer refers to a remote file, as determined by
`file-remote-p'.
383 384

No suitable syntax checker exists for the current buffer.
385 386

Return t if Flycheck mode may be enabled, and nil otherwise."
387
  (and (not (flycheck-temporary-buffer-p))
388
       (not (and (buffer-file-name) (file-remote-p (buffer-file-name) 'method)))
389 390 391 392 393 394 395 396 397 398
       (flycheck-get-checker-for-buffer)))

(defun flycheck-mode-on-safe ()
  "Enable `flycheck-mode' if it is safe to do so.

`flycheck-mode' is only enabled if `flycheck-may-enable-mode'
returns t."
  (when (flycheck-may-enable-mode)
    (flycheck-mode)))

399
;;;###autoload
400 401 402
(define-globalized-minor-mode global-flycheck-mode flycheck-mode
  flycheck-mode-on-safe
  :init-value nil
403 404
  :group 'flycheck
  :require 'flycheck)
405

406 407

;;; Manual syntax checking
408 409 410
(defun flycheck-clear ()
  "Clear all errors in the current buffer."
  (interactive)
411
  (flycheck-delete-all-overlays)
412 413
  (flycheck-clear-errors)
  (flycheck-hide-error-buffer))
414 415 416 417

(defun flycheck-buffer ()
  "Check syntax in the current buffer."
  (interactive)
418
  (flycheck-clean-deferred-check)
419
  (if flycheck-mode
420
      (unless (flycheck-running-p)
421 422 423 424 425 426
        ;; 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.
        (flycheck-clear-errors)
        (flycheck-mark-all-overlays-for-deletion)
427
        (condition-case err
428
            (let ((checker (flycheck-get-checker-for-buffer)))
429 430
              (if checker
                  (flycheck-start-checker checker)
431
                (flycheck-clear)
432
                (flycheck-report-status "-")))
433
          (error
434
           (flycheck-report-error)
435
           (signal (car err) (cdr err)))))
436
    (user-error "Flycheck mode disabled")))
437

438 439 440 441
(defun flycheck-compile-name (_name)
  "Get a name for a Flycheck compilation buffer.

_NAME is ignored."
442 443 444 445 446 447
  (format "*Flycheck %s*" (buffer-file-name)))

(defun flycheck-compile ()
  "Run syntax checker as compiler."
  (interactive)
  (unless (buffer-file-name)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
448
    (user-error "Cannot compile buffers without backing file"))
449 450 451 452 453 454 455 456
  (let ((checker (flycheck-get-checker-for-buffer)))
    (if checker
        (let* ((command (flycheck-checker-shell-command checker))
               (buffer (compilation-start command nil
                                          #'flycheck-compile-name)))
          (with-current-buffer buffer
            (set (make-local-variable 'compilation-error-regexp-alist)
                 (flycheck-checker-compilation-error-regexp-alist checker))))
Sebastian Wiesner's avatar
Sebastian Wiesner committed
457
      (user-error "No suitable checker available"))))
458

459 460 461 462

;;;; Deferred syntax checking
(defvar-local flycheck-deferred-syntax-check nil
  "If non-nil, a deferred syntax check is pending.")
463 464 465 466 467 468 469 470

(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.

Return t if the check is to be deferred, or nil otherwise."
  (not (get-buffer-window)))
471

472 473
(defun flycheck-deferred-check-p ()
  "Determine whether the current buffer has a deferred check.
474

475 476
Return t if so, or nil otherwise."
  flycheck-deferred-syntax-check)
477

478 479 480 481 482 483 484
(defun flycheck-buffer-deferred ()
  "Defer syntax check for the current buffer."
  (setq flycheck-deferred-syntax-check t))

(defun flycheck-clean-deferred-check ()
  "Clean an deferred syntax checking state."
  (setq flycheck-deferred-syntax-check nil))
485

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
(defun flycheck-perform-deferred-syntax-check ()
  "Perform any deferred syntax checks."
  (when (flycheck-deferred-check-p)
    (flycheck-clean-deferred-check)
    (flycheck-buffer-automatically)))


;;;; Automatic syntax checking
(defun flycheck-may-check-automatically (&optional condition)
  "Determine whether the buffer may be checked under CONDITION.

Read-only buffers may never be checked automatically.

If CONDITION is non-nil, determine whether syntax may checked
automatically according to
`flycheck-check-syntax-automatically'."
  (and (not buffer-read-only)
       (or (not condition)
           (memq condition flycheck-check-syntax-automatically))))

(defun flycheck-buffer-automatically (&optional condition)
  "Automatically check syntax at CONDITION.

Syntax is not checked if `flycheck-may-check-automatically'
returns nil for CONDITION.

The syntax check is deferred if `flycheck-must-defer-check'
returns t."
  (if (flycheck-may-check-automatically condition)
515 516 517 518 519 520
      (if (flycheck-must-defer-check)
          (flycheck-buffer-deferred)
        (with-demoted-errors
          (flycheck-buffer)))
    (message "Cannot perform a syntax check in buffer %s."
             (buffer-name))))
521

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
(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."
  (when (and flycheck-mode
             (s-contains? "\n" (buffer-substring beg end)))
    (flycheck-buffer-automatically 'new-line)))

(defun flycheck-handle-save ()
  "Handle a save of the buffer."
  (flycheck-buffer-automatically 'save))

Sebastian Wiesner's avatar
Sebastian Wiesner committed
538

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
;;;; Mode line reporting
(defun flycheck-report-status (status)
  "Report Flycheck STATUS."
  (let ((mode-line flycheck-mode-line-lighter))
    (setq mode-line (concat mode-line status))
    (setq flycheck-mode-line mode-line)
    (force-mode-line-update)))

(defun flycheck-report-error ()
  "Report a Flycheck error status.

Clears all Flycheck errors first."
  (flycheck-clear)
  (flycheck-report-status "!"))

(defun flycheck-report-error-count (errors)
  "Report ERRORS in the current buffer.

Report a proper flycheck status."
  (if errors
      (let ((no-err-warnings (flycheck-count-errors errors)))
        (flycheck-report-status
         (format ":%s/%s" (car no-err-warnings) (cdr no-err-warnings))))
    (flycheck-report-status "")))

Sebastian Wiesner's avatar
Sebastian Wiesner committed
564

565
;;;; Utility functions
566 567 568 569 570 571 572 573 574
(defun flycheck-string-to-number-safe (string)
  "Safely convert STRING to a number.

If STRING is of string type, and a numeric string (see
`s-numeric?'), convert STRING to a number and return it.
Otherwise return nil."
  (when (and (stringp string) (s-numeric? string))
    (string-to-number string)))

575 576 577 578 579 580
(defvar-local flycheck-temp-files nil
  "A list of temporary files created by Flycheck.")

(defvar-local flycheck-temp-directories nil
  "A list of all temporary directories created by Flycheckg.")

581 582 583 584 585 586
(defun flycheck-temp-dir-system (prefix)
  "Create a unique temporary directory from PREFIX.

Add the directory to `flycheck-temp-directories'.

Return the path of the directory"
587 588 589
  (let* ((tempdir (make-temp-file prefix :directory)))
    (add-to-list 'flycheck-temp-directories tempdir)
    tempdir))
590

591
(defun flycheck-temp-file-system (filename prefix)
592
  "Create a temporary file named after FILENAME with PREFIX.
593

594 595 596 597 598 599 600 601 602 603
If FILENAME is nil, this function creates a temporary file with
PREFIX and a random suffix.  The path of the file is added to
`flycheck-temp-files'.

If FILENAME is non-nil, this function creates a temporary
directory with PREFIX and a random suffix using
`flycheck-temp-dir-system', and creates a file with the same name
as FILENAME in this directory.  The path of the file is *not*
added to `flycheck-temp-files', because the directory is already
tracked as temp file.
604

605
Return the path of the file."
606 607 608 609 610
  ;; HACK: Prevent re-compression to work around a supposed bug in Emacs.
  ;; `make-temp-file' calls `write-region' to set the contents of the new
  ;; temporary file, which in turn calls `jka-compr-write-region' for compressed
  ;; files. If `jka-compr-really-do-compress' is non-nil this function uses END
  ;; even though START is a string, hence breaking the `write-region' API that
611
  ;; we rely on.  Report upstream!
612 613 614 615 616 617 618
  (let ((jka-compr-really-do-compress nil)
        tempfile)
    (if filename
        (let ((directory (flycheck-temp-dir-system prefix)))
          (setq tempfile (expand-file-name (file-name-nondirectory filename)
                                           directory)))
      (setq tempfile (make-temp-file prefix)))
619 620
    (add-to-list 'flycheck-temp-files tempfile)
    tempfile))
621

622
(defun flycheck-temp-file-inplace (filename prefix)
623 624
  "Create an in-place copy of FILENAME with PREFIX added.

625 626
Add the path of the file to `flycheck-temp-files'.

627
If FILENAME is nil, fall back to `flycheck-temp-file-system'.
628 629 630 631

Return the path of the file."
  (if filename
      (let* ((directory (file-name-directory filename))
632 633 634 635 636
             (name (file-name-nondirectory filename))
             (tempname (format "%s-%s" prefix name))
             (tempfile (expand-file-name tempname directory)))
        (add-to-list 'flycheck-temp-files tempfile)
        tempfile)
637
    ;; With no filename, fall back to a copy in the system directory.
638
    (flycheck-temp-file-system filename prefix)))
639

640 641 642 643 644 645 646
(defun flycheck-root-directory-p (directory)
  "Determine if DIRECTORY is the root directory.

In order to work in work in a platform-neutral way,
check to see if DIRECTORY is its own parent.

Return t if root directory, otherwise nil."
647 648
  (string= (directory-file-name directory)
           (file-name-directory (directory-file-name directory))))
649

650
(defun flycheck-find-file-in-tree (filename directory)
651
  "Find FILENAME in DIRECTORY and all of its ancestors.
652

653 654 655
Start looking for a file named FILENAME in DIRECTORY and traverse
upwards through all of its ancestors up to the file system root
until the file is found or the root is reached.
656 657

Return the absolute path of the file, or nil if the file was not
658 659
found in DIRECTORY or any of its ancestors."
  (let ((full-path (expand-file-name filename directory)))
660 661 662 663 664 665 666 667 668
    (cond
     ((flycheck-root-directory-p directory)
      (when (file-exists-p full-path) full-path))
     ((file-exists-p full-path) full-path)
     (:else
      (let ((parent-directory (file-name-directory
                               (directory-file-name
                                (file-name-directory full-path)))))
        (flycheck-find-file-in-tree filename parent-directory))))))
Sebastian Wiesner's avatar
Sebastian Wiesner committed
669

670 671 672 673 674
(defun flycheck-find-file-for-buffer (filename)
  "Find FILENAME for the current buffer.

First try to find the file in the buffer's directory and any of
its ancestors (see `flycheck-find-file-in-tree').  If that fails
675 676 677 678 679 680
or if the buffer has no `buffer-file-name' try to find the file
in the home directory.  If the file is not found anywhere return
nil."
  (let ((directory (when (buffer-file-name)
                     (file-name-directory (buffer-file-name)))))
    (or (when directory (flycheck-find-file-in-tree filename directory))
681
        (let ((home-path (expand-file-name filename "~")))
682 683
          (when (file-exists-p home-path) home-path)))))

684 685 686
(defun flycheck-canonical-file-name (filename)
  "Turn FILENAME into canonical form.

687 688 689 690
Return FILENAME expanded and fully resolved, in a canonical form
without double slashes and without trailing slash, i.e. in a form
suitable for comparison of file names."
  (directory-file-name (file-truename filename)))
691

692
(defun flycheck-same-files-p (file1 file2)
693 694 695 696
  "Determine whether two files FILE1 and FILE2 are the same."
  (string= (flycheck-canonical-file-name file1)
           (flycheck-canonical-file-name file2)))

697 698 699 700 701
(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)
  (write-region nil nil file-name nil 0))

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
(defun flycheck-option-with-value-argument (option value)
  "Create arguments specifying OPTION with VALUE.

OPTION is a string denoting the option to pass, VALUE a string
containing the value for this option.

If OPTION ends with a equal sign =, OPTION and VALUE are
concatenated to a single string, which is then wrapped in a list
and returned.

Otherwise `(list OPTION VALUE)' is returned."
  (if (s-ends-with? "=" option)
      (list (concat option value))
    (list option value)))

717 718 719 720 721 722 723
(defun flycheck-temporary-buffer-p ()
  "Determine whether the current buffer is a temporary buffer.

Buffers whose names start with a space are considered temporary
buffers."
  (s-starts-with? " " (buffer-name)))

724
(defun flycheck-safe-delete-files (files)
725
  "Safely delete FILES."
726 727 728
  (--each files (ignore-errors (delete-file it))))

(defun flycheck-safe-delete-directories (directories)
729
  "Safely delete DIRECTORIES."
730 731
  (--each directories (ignore-errors (delete-directory it :recursive))))

732 733 734 735 736 737 738 739 740 741 742
(defun flycheck-safe-delete-temporaries ()
  "Safely delete all temp files and directories of Flycheck.

Safely delete all files listed in `flycheck-temp-files' and all
directories in `flycheck-temp-directories', and set both
variables to nil."
  (flycheck-safe-delete-directories flycheck-temp-directories)
  (flycheck-safe-delete-files flycheck-temp-files)
  (setq flycheck-temp-directories nil
        flycheck-temp-files nil))

Sebastian Wiesner's avatar
Sebastian Wiesner committed
743

744 745 746 747 748 749 750 751 752
;;;; Minibuffer tools
(defvar read-flycheck-checker-history nil
  "History of `read-flycheck-checker'.")

(defun read-flycheck-checker (prompt)
  "Read a flycheck checker from minibuffer with PROMPT.

Return the checker as symbol, or nil if no checker was
chosen."
753
  (let* ((input (completing-read prompt obarray
754 755 756 757
                                 #'flycheck-valid-checker-p t
                                 nil 'read-flycheck-checker-history)))
    (if (string= input "") nil (intern input))))

Sebastian Wiesner's avatar
Sebastian Wiesner committed
758

759
;;;; Checker declarations
760
;;;###autoload
761
(defmacro flycheck-declare-checker (symbol docstring &rest properties)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
762 763 764 765 766 767
  "Declare SYMBOL as syntax checker with DOCSTRING and PROPERTIES.

DOCSTRING provides documentation for the new checker.  Use
`flycheck-checker-documentation' to access the documentation
string of a checker, and `flycheck-describe-checker' to get help
about a checker.
768 769 770

The following PROPERTIES are understood:

771
`:command' A list with the executable (in `car') and the
772 773 774 775 776 777 778
arguments (in `cdr') of the syntax checker.  The executable is
checked for existence with `executable-find' before executing the
checker.  The arguments are substituted with
`flycheck-substitute-argument' before execution, see the
documentation of this function for a list of special tags allowed
in arguments.

779
`:error-patterns' A list of error patterns to parse the output of
780 781 782 783 784 785 786 787 788
the checker.  Each pattern is a list (REGEXP LEVEL).  REGEXP is a
regular expression that matches an error.  This regular
expression may contain match groups extracting specific
information about the error.  The 1st group is the file name, the
2nd group the line number, the 3rd group the column number and
the 4th group the error message.  A group is ignored if it did
not match or the match returned an empty string.  LEVEL is either
warning or error and determines the severity of the error message
parsed with the pattern.
789

790
`:error-parser' A function symbol to parse errors with.  The
791 792 793 794 795
function must accept three arguments OUTPUT CHECKER BUFFER, where
OUTPUT is the output as string and CHECKER the checker symbol
that was used to check BUFFER.  The function must return a list
of `flycheck-error' objects parsed from OUTPUT.

796
`:modes' A major mode symbol or a list thereof.  If present the
797 798
checker is only used in these modes.

799
`:predicate' An Emacs Lisp form.  If present the checker is only
Sebastian Wiesner's avatar
Sebastian Wiesner committed
800 801
used if the form evaluates to a non-nil result in the buffer to
check.
802

803
`:next-checkers' A list where each element is either a checker
804
symbol to run after this checker or a cons cell (PREDICATE
805 806 807 808 809 810 811 812 813 814 815 816
. CHECKER).  In the latter case, CHECKER is the checker symbol to
run, and the PREDICATE symbol specifies when to run the checker:
If PREDICATE is `no-errors' run the next checker only if this
checker returned no errors at all.  If PREDICATE is
`warnings-only', run the next checker only if this checker
returned only warnings.  Only the first usable and
registered (see `flycheck-registered-checker-p') is run.

A checker must have a `:command' property, either
`:error-patterns' or `:error-parser' (but not both), and at least
one of `:predicate' and `:modes'.  If `:predicate' and `:modes'
are present, both must match for the checker to be used."
817 818
  (declare (indent 1)
           (doc-string 2))
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
  `(flycheck--declare-checker-1 (quote ,symbol) ,docstring ,@properties)
  )

(defun flycheck-undeclare-checker (symbol)
  "Un-declare the syntax checker denoted by SYMBOL."
  (--each
      '(:flycheck-checker :flycheck-command :flycheck-error-parser
                          :flycheck-error-patterns :flycheck-modes
                          :flycheck-predicate :flycheck-next-checkers
                          :flycheck-documentation :flycheck-file)
    (put symbol it nil)))

(defun flycheck--declare-checker-1 (symbol docstring &rest properties)
  "Declare SYMBOL as checker with DOCSTRING and PROPERTIES."
  ;; Un-declare any previous checker for this mode
  (flycheck-undeclare-checker symbol)
  ;; Store the checker properties
  (put symbol :flycheck-command (plist-get properties :command))
  (put symbol :flycheck-error-patterns (plist-get properties :error-patterns))
  (put symbol :flycheck-error-parser (plist-get properties :error-parser))
  (put symbol :flycheck-modes (plist-get properties :modes))
  (put symbol :flycheck-predicate (plist-get properties :predicate))
  (put symbol :flycheck-next-checkers (plist-get properties :next-checkers))
  (put symbol :flycheck-documentation docstring)
  ;; Record the location of the definition of the checker.  If we're loading
  ;; from a file, record the file loaded from.  Otherwise use the current
  ;; buffer name, in case of `eval-buffer' and the like.
846 847
  (-when-let (filename (if load-in-progress load-file-name (buffer-file-name)))
    (when (s-ends-with? ".elc" filename)
848 849 850 851 852 853
      (setq filename (s-chop-suffix "c" filename)))
    (put symbol :flycheck-file filename))
  ;; Verify the checker and declare it valid if succeeded
  (flycheck-verify-checker symbol)
  (put symbol :flycheck-checker t))

854

855
;;;###autoload
856 857 858 859 860 861 862 863
(defmacro flycheck-def-config-file-var (symbol checker &optional file-name)
  "Define SYMBOL as config file variable for CHECKER, with default FILE-NAME.

SYMBOL is declared as customizable variable (see `defcustom`)
providing a configuration file for CHECKER.  The CHECKER argument
is used for documentation purposes only.  If given use FILE-NAME
as initial value.

Sebastian Wiesner's avatar
Sebastian Wiesner committed
864 865
Use this together with the `config-file' cell in syntax checker
commands."
866 867
  (declare (indent 3))
  `(progn
868
     (put (quote ,checker) :flycheck-config-file-var (quote ,symbol))
869
     (defcustom ,symbol ,file-name
870
       ,(format "Configuration file for `%s'.
871 872 873 874 875 876 877 878 879

When set to a plain file name without any slash search for this
file name in the directory of the buffer being check, any
ancestors thereof or the home directory.  If buffer being checked
has no backing file, search in the home directory only.  If the
file is found pass it to the checker as configuration file.
Otherwise invoke the checker without a configuration file.

When set to a file path containing a slash expand the file name
880
with `expand-file-named' and pass this file to checker, if it
881 882 883 884 885 886 887 888
exists.  Otherwise invoke the checker without a configuration
file.

Use this variable as file-local variable if you need a specific
configuration file a buffer." checker)
       :type '(choice (const :tag "No configuration file" nil)
                      (string :tag "File name or path"))
       :group 'flycheck-config-files)
889 890
     (put (quote ,symbol) 'safe-local-variable #'stringp)
     (make-variable-buffer-local (quote ,symbol))))
891

892 893 894 895 896 897 898 899 900 901 902 903 904
;;;###autoload
(defmacro flycheck-def-option-var (symbol init-value checker docstring
                                          &rest custom-args)
  "Define SYMBOL as option variable with INIT-VALUE for CHECKER.

INIT-VALUE is the initial value for the new variable.  DOCSTRING
is its docstring.

The variable is declared with `defcustom', and declared
buffer-local.  CUSTOM-ARGS are forwarded to `defcustom'.

Use this together with the `option' cell in syntax checker
commands."
905 906
  (declare (indent 3)
           (doc-string 4))
907 908 909 910 911 912 913 914 915 916 917 918
  `(progn
     (let ((options (flycheck-checker-option-vars (quote ,checker))))
       (put (quote ,checker) :flycheck-option-vars
            (-uniq (cons (quote ,symbol) options))))
     (defcustom ,symbol ,init-value
       ,(format "%s

This variable is an option for the syntax checker `%s'." docstring checker)
       :group 'flycheck-options
       ,@custom-args)
     (make-variable-buffer-local (quote ,symbol))))

919 920 921 922
(defun flycheck-error-pattern-p (pattern)
  "Check whether PATTERN is a valid error pattern."
  (and
   (listp pattern)                      ; A pattern must be a list...
923 924
   (= (length pattern) 2)               ; ...of length 2...
   (stringp (car pattern))              ; ...whose 1st element is a string
925
   (memq (cadr pattern) '(warning error)) ; ...and whose 2nd element a category
926
   ))
927

928 929 930
(defun flycheck-error-patterns-list-p (patterns)
  "Check whether PATTERNS is a list of valid error patterns."
  (-all? 'flycheck-error-pattern-p patterns))
931

932 933
(defun flycheck-command-argument-cell-p (cell)
  "Determine whether CELL is a valid argument cell."
934 935 936 937 938 939 940 941 942 943 944
  (pcase cell
    (`(config-file ,option-name ,config-file-var)
     (and (stringp option-name)
          (symbolp config-file-var)))
    (`(option ,option-name ,option-var)
     (and (stringp option-name)
          (symbolp option-var)))
    (`(option ,option-name ,option-var ,filter)
     (and (stringp option-name)
          (symbolp option-var)
          (symbolp filter)))
945
    (`(eval ,_) t)
946
    (_ nil)))
947

948 949 950
(defun flycheck-command-argument-p (arg)
  "Check whether ARG is a valid command argument."
  (or
951
   (memq arg '(source source-inplace source-original temporary-directory))
952
   (stringp arg)
953
   (and (listp arg) (flycheck-command-argument-cell-p arg))))
954 955 956 957 958

(defun flycheck-command-arguments-list-p (arguments)
  "Check whether ARGUMENTS is a list of valid arguments."
  (-all? 'flycheck-command-argument-p arguments))

959 960 961 962 963 964 965
(defun flycheck-verify-checker (checker)
  "Verify CHECKER.

Ensure that all required properties are present, and signal an
error if not."
  (let ((command (get checker :flycheck-command))
        (patterns (get checker :flycheck-error-patterns))
966
        (parser (get checker :flycheck-error-parser))
967
        (modes (get checker :flycheck-modes))
968
        (predicate (get checker :flycheck-predicate))
969
        (next-checkers (get checker :flycheck-next-checkers))
970 971
        (doc (get checker :flycheck-documentation)))
    (unless (and doc (stringp doc))
972
      (error "Checker %s must have documentation" checker))
973
    (unless command
974
      (error "Checker %s must have a :command" checker))
975
    (unless (stringp (car command))
976
      (error "Checker %s must have an executable in :command" checker))
977 978
    (unless (flycheck-command-arguments-list-p command)
      (error "Checker %s has invalid :command arguments" checker))
979 980 981 982 983 984
    (unless (or patterns parser)
      (error "Checker %s must have an :error-parser or :error-patterns" checker))
    (when (and patterns parser)
      (error "Checker %s must not have :error-parser and :error-patterns"
             checker))
    (unless (or (null patterns) (flycheck-error-patterns-list-p patterns))
985
      (error "Checker %s has invalid :error-patterns" checker))
986 987 988
    (unless (or (null parser) (fboundp parser))
      (error "Function definition of error parser %s of checker %s is void"
             parser checker))
989
    (unless (or modes predicate)
990
      (error "Checker %s must have :modes or :predicate" checker))
991 992 993 994 995 996 997 998
    (unless (or
             (null next-checkers)
             (and (listp next-checkers)
                  (--all? (or (symbolp it)
                              (and (listp it)
                                   (memq (car it) '(no-errors warnings-only))
                                   (symbolp (cdr it))))
                          next-checkers)))
999
      (error "Checker %s has invalid next checkers" checker))))
1000

Sebastian Wiesner's avatar
Sebastian Wiesner committed
1001

1002
;;;; Checker API
1003
(defun flycheck-declared-checkers ()
1004 1005 1006 1007
  "Find all declared syntax checkers.

The returned list is sorted alphapetically by the symbol name of
the syntax checkers."
1008 1009 1010 1011 1012 1013
  (let (declared-checkers)
    (mapatoms (lambda (symbol)
                (when (flycheck-valid-checker-p symbol)
                  (push symbol declared-checkers))))
    (sort declared-checkers #'string<)))

1014 1015 1016 1017 1018 1019
(defun flycheck-registered-checker-p (checker)
  "Determine whether CHECKER is registered.

A checker is registered if it is contained in `flycheck-checkers'."
  (memq checker flycheck-checkers))

1020 1021
(defun flycheck-valid-checker-p (checker)
  "Check whether a CHECKER is valid.
1022

1023 1024 1025
A valid checker is a symbol declared as checker with
`flycheck-declare-checker'."
  (get checker :flycheck-checker))
1026

1027
(defun flycheck-checker-modes (checker)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
1028
  "Get the modes of CHECKER."
1029
  (let ((modes (get checker :flycheck-modes)))
1030
    (if (and modes (symbolp modes))
1031 1032 1033
        (list modes)
      modes)))

1034 1035 1036 1037
(defun flycheck-checker-predicate (checker)
  "Get the predicate of CHECKER."
  (get checker :flycheck-predicate))

1038 1039 1040 1041
(defun flycheck-checker-next-checkers (checker)
  "Get the next checkers for CHECKER."
  (get checker :flycheck-next-checkers))

1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
(defun flycheck-checker-command (checker)
  "Get the raw command of CHECKER.

The command list returned by this function is not substituted,
and hence still contains special tags and symbols.  Use
`flycheck-checker-substituted-command' to get an executable
command list with no special tags and symbols."
  (get checker :flycheck-command))

(defun flycheck-checker-executable (checker)
  "Get the executable of CHECKER.

The executable is the `car' of the checker command as returned by
`flycheck-checker-command'."
  (car (flycheck-checker-command checker)))

(defun flycheck-checker-error-patterns (checker)
  "Get the error patterns of CHECKER."
  (get checker :flycheck-error-patterns))

1062 1063 1064 1065
(defun flycheck-checker-error-parser (checker)
  "Get the error parser of CHECKER."
  (get checker :flycheck-error-parser))

1066 1067 1068 1069 1070 1071 1072
(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 (cadr pattern))
1073 1074 1075
         (level-no (pcase level
                     (`error 2)
                     (`warning 1))))
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
    (list regexp 1 2 3 level-no)))

(defun flycheck-checker-compilation-error-regexp-alist (checker)
  "Convert error patterns of CHECKER for use with compile.el.

Return an alist of all error patterns of CHECKER, suitable for
use with `compilation-error-regexp-alist'."
  (-map #'flycheck-checker-pattern-to-error-regexp
        (flycheck-checker-error-patterns checker)))

1086 1087 1088 1089
(defun flycheck-checker-documentation (checker)
  "Get the documentation of CHECKER."
  (documentation-property checker :flycheck-documentation))

1090 1091 1092 1093 1094 1095
(defun flycheck-checker-file (checker)
  "Get the file CHECKER was defined in.

Return nil if the file cannot be determined."
  (get checker :flycheck-file))

1096 1097 1098 1099 1100 1101 1102
(defun flycheck-checker-config-file-var (checker)
  "Get the associated configuration file variable of CHECKER.

Return nil if CHECKER has no associated configuration file
variable."
  (get checker :flycheck-config-file-var))

1103 1104 1105 1106 1107 1108
(defun flycheck-checker-option-vars (checker)
  "Get the associated option variables of CHECKER.

Return a (possibly empty) list of variable symbols."
  (get checker :flycheck-option-vars))

1109 1110
(defun flycheck-check-modes (checker)
  "Check the allowed modes of CHECKER.
1111

1112 1113
Check the current `major-mode' against the modes allowed for
CHECKER.  Return t if the modes match or nil otherwise."
1114
  (let ((modes (flycheck-checker-modes checker)))
1115
    (or (not modes) (memq major-mode modes))))
1116

1117 1118
(defun flycheck-check-predicate (checker)
  "Check the predicate of CHECKER.
1119

1120 1121
Check the predicate of CHECKER, and return t if the checker has
no predicate or the result of the predicate evaluation."
1122
  (let ((predicate (flycheck-checker-predicate checker)))
1123 1124
    (or (not predicate) (eval predicate))))

1125 1126
(defun flycheck-check-executable (checker)
  "Check the executable of the CHECKER."
1127
  (when (executable-find (flycheck-checker-executable checker)) t))
1128

1129 1130
(defun flycheck-may-use-checker (checker)
  "Determine whether a CHECKER may be used.
1131

1132 1133 1134 1135 1136 1137 1138 1139
Return t if CHECKER may be used for the current buffer and nil
otherwise."
  (unless (flycheck-valid-checker-p checker)
    (error "%s is no declared flycheck syntax checker (see `flycheck-declare-checker')"
           checker))
  (and (flycheck-check-modes checker)
       (flycheck-check-predicate checker)
       (flycheck-check-executable checker)))
1140

1141 1142 1143
(defun flycheck-may-use-next-checker (next-checker)
  "Determine whether NEXT-CHECKER may be used."
  (when (symbolp next-checker)
Sebastian Wiesner's avatar
Sebastian Wiesner committed
1144
    (setq next-checker (cons t next-checker)))
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
  (let ((predicate (car next-checker))
        (next-checker (cdr next-checker)))
    (and (or (eq predicate t)
             (and (eq predicate 'no-errors)
                  (not (flycheck-has-current-errors-p)))
             (and (eq predicate 'warnings-only)
                  (not (flycheck-has-current-errors-p 'error))))
         (flycheck-registered-checker-p next-checker)
         (flycheck-may-use-checker next-checker))))

1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
(defun flycheck-find-config-file (file-name)
  "Find the configuration file FILE-NAME.

If FILE-NAME contains a slash, return FILE-NAME expanded with
`expand-file-name'.

If FILE-NAME does not contain a slash, search the file with
`flycheck-find-file-name' and return the result."
  (when file-name
    (if (s-contains? "/" file-name)
1165 1166
        (let ((file-name (expand-file-name file-name)))
          (when (file-exists-p file-name) file-name))
1167
      (flycheck-find-file-for-buffer file-name))))
1168

1169 1170
(defun flycheck-substitute-argument-cell (cell)
  "Substitute an argument CELL.
1171

1172 1173 1174 1175
Generally, a CELL is a form `(SYMBOL ARGS...) where SYMBOL is a special tag,
and ARGS the arguments for this tag.

If CELL is a form `(config-file OPTION VARIABLE)' search the
1176
configuration file bound to VARIABLE with
1177
`flycheck-find-config-file' and return a list of arguments that
1178 1179 1180 1181 1182 1183
pass this configuration file to the syntax checker, or nil if the
configuration file was not found.  If OPTION ends with a =
character, the returned list contains a single element only,
being the concatenation of OPTION and the path of the
configuration file.  Otherwise the list has two items, the first
being OPTION, the second the path of the configuration file.
1184

1185 1186 1187 1188 1189 1190 1191
If CELL is a form `(option OPTION VARIABLE [FILTER])' retrieve
the value of VARIABLE and return a list of arguments that pass
this value as value for OPTION to the syntax checker.  FILTER is
an optional function to be applied to the value of VARIABLE.
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.  If OPTION ends with a =, process it like in a
1192 1193
`config-file' cell (see above).

1194
If CELL is a form `(eval FORM), return the result of evaluating
1195 1196 1197 1198 1199 1200
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.  In case of other return values
an error is signaled.  _No_ further substitutions are performed,
neither in FORM before it is evaluated, nor in the result of
evaluating FORM.
1201 1202

In all other cases, signal an error."
1203 1204
  (pcase cell
    (`(config-file ,option-name ,file-name-var)
1205 1206 1207
     (-when-let* ((value (symbol-value file-name-var))
                  (file-name (flycheck-find-config-file value)))
       (flycheck-option-with-value-argument option-name file-name)))
1208
    (`(option ,option-name ,variable)
1209 1210 1211 1212 1213
     (-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-option-with-value-argument option-name value)))
1214
    (`(option ,option-name ,variable ,filter)
1215 1216 1217 1218 1219
     (-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-option-with-value-argument option-name value)))
1220
    (`(eval ,form)
1221
     (let ((result (eval form)))
1222 1223 1224 1225 1226 1227
       (if (or (null result)
               (stringp result)
               (and (listp result) (-all? #'stringp result)))
           result
         (error "Invalid result from evaluation of %S: %S" form result))))
    (_ (error "Unsupported argument cell %S" cell))))
1228

1229 1230 1231
(defun flycheck-substitute-argument-symbol (symbol)
  "Substitute an argument SYMBOL.

1232 1233 1234 1235
If SYMBOL is `source' or `source-inplace', create a temporary
file to check and return its path.  With `source', try to retain
the non-directory component of the buffer's file name in the
temporary file.
1236

1237
If SYMBOL is `source-original', return the path of the actual file
1238 1239
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
1240 1241
contents of the buffer to check.  Do not use this as primary
input to a checker!
1242

1243 1244 1245
If SYMBOL is `temporary-directory', create a unique temporary
directory and return its path.

1246
In all other cases, signal an error."
1247
  (cl-case symbol
1248
    (source
1249 1250 1251
     (let ((filename (flycheck-temp-file-system (buffer-file-name) "flycheck")))
       (flycheck-save-buffer-to-file filename)
       filename))
1252
    (source-inplace
1253 1254 1255
     (let ((filename (flycheck-temp-file-inplace (buffer-file-name) "flycheck")))
       (flycheck-save-buffer-to-file filename)
       filename))
1256 1257
    (source-original
     (or (buffer-file-name) ""))
1258
    (temporary-directory
1259
     (flycheck-temp-dir-system "flycheck"))
1260 1261
    (t
     (error "Unsupported argument symbol %S" symbol))))
1262

1263 1264 1265 1266 1267
(defun flycheck-substitute-argument (arg)
  "Substitute ARG with file to check is possible.

If ARG is a string, return ARG unchanged.

Sebastian Wiesner's avatar
Sebastian Wiesner committed
1268 1269 1270
If ARG is a symbol, substitute it with
`flycheck-substitute-argument-symbol'.

1271 1272
If ARG is a list, substitute it with
`flycheck-substitute-argument-cell'.
1273

1274
In all other cases, signal an error."
1275
  (cond
1276 1277 1278
   ((stringp arg) arg)
   ((symbolp arg) (flycheck-substitute-argument-symbol arg))
   ((listp arg) (flycheck-substitute-argument-cell arg))
1279
   (:else (error "Unsupported argument %S" arg))))
1280

1281
(defun flycheck-checker-substituted-command (checker)
1282
  "Get the substituted command of a CHECKER.
1283

1284
Substitute each argument in the command of CHECKER using
1285 1286
`flycheck-substitute-argument'.  This replaces any special
symbols in the command."
1287
  (-flatten (-keep #'flycheck-substitute-argument
1288
                   (flycheck-checker-command checker))))
1289

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
(defun flycheck-substitute-shell-argument-symbol (symbol)
  "Substitute a shell argument SYMBOL.

If SYMBOL is `source', `source-inplace' or `source-original',
return the buffer file name quoted with `shell-quote-argument'.

Otherwise signal an error."
  (if (memq symbol '(source source-inplace source-original))
      (shell-quote-argument (buffer-file-name))
    (error "Unsupported argument symbol %S" symbol)))

(defun flycheck-substitute-shell-argument-cell (cell)
  "Substitute a shell argument CELL.

Like `flycheck-substitute-argument-cell', but return a single
string suitable for a shell command, i.e. quoted as necessary
with `shell-quote-argument'."
  (let ((args (flycheck-substitute-argument-cell cell)))
    (if (stringp args)
        (shell-quote-argument args)
      (s-join " " (-map #'shell-quote-argument args)))))

1312
(defun flycheck-substitute-shell-argument (arg)
1313
  "Substitute ARG with file to check is possible.
1314

1315 1316
If ARG is a string, return ARG quoted with
`shell-quote-argument'.
1317

1318 1319 1320 1321 1322
If ARG is a symbol, substitute it with
`flycheck-substitute-shell-argument-symbol'.

If ARG is a list, substitute it with
`flycheck-substitute-shell-argument-cell'.
1323

1324
In all other cases, signal an error."
1325
  (cond
1326 1327 1328 1329
   ((stringp arg) (shell-quote-argument arg))
   ((symbolp arg) (flycheck-substitute-shell-argument-symbol arg))
   ((listp arg) (flycheck-substitute-shell-argument-cell arg))
   (:else (error "Unsupported argument %S" arg))))
1330 1331 1332 1333

(defun flycheck-checker-shell-command (checker)
  "Get a shell command for CHECKER.

1334 1335 1336 1337
Substitutions are performed like in
`flycheck-checker-substituted-command', but with
`flycheck-substitute-shell-argument'.

1338 1339 1340 1341
Return the command of CHECKER as single string, suitable for
shell execution."
  (s-join " " (-map #'flycheck-substitute-shell-argument
                    (flycheck-checker-command checker))))
1342

Sebastian Wiesner's avatar
Sebastian Wiesner committed
1343

1344 1345 1346 1347 1348 1349 1350 1351 1352
;;;; Option filters
(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."
  (when value
    (number-to-string value)))

Sebastian Wiesner's avatar
Sebastian Wiesner committed
1353

1354
;;;; Checker selection
1355
(defvar-local flycheck-last-checker nil
1356 1357
  "The last checker used for the current buffer.")

1358 1359 1360 1361
(defun flycheck-clear-checker ()
  "Clear configured and remembered checkers in the current buffer."
  (setq flycheck-last-checker nil))

1362 1363 1364
(defun flycheck-try-last-checker-for-buffer ()
  "Try the last checker for the current buffer.

1365
Return the checker if it may be used, or nil otherwise."
1366 1367
  ;; We should not use the last checker if it was removed from the list of
  ;; allowed checkers in the meantime
1368 1369 1370
  (when (and (flycheck-registered-checker-p flycheck-last-checker)
             (flycheck-may-use-checker flycheck-last-checker))
    flycheck-last-checker))
1371 1372 1373 1374 1375 1376 1377

(defun flycheck-get-new-checker-for-buffer ()
  "Find a new checker for the current buffer.

If a checker is found set `flycheck-last-checker' to re-use this
checker for the next check.

1378
Return the checker if there is any, or nil otherwise."
1379 1380
  (-when-let (checker (-first #'flycheck-may-use-checker flycheck-checkers))
    (setq flycheck-last-checker checker)))
1381

1382 1383
(defun flycheck-get-checker-for-buffer ()
  "Find the checker for the current buffer.
1384

1385 1386
Return checker if there is a checker for the current buffer, or
nil otherwise."
1387 1388
  (if flycheck-checker
      ;; If a checker was configured, try to use it!
1389 1390
      (if (flycheck-may-use-checker flycheck-checker)
          flycheck-checker
1391 1392
        (user-error "Configured syntax checker %s cannot be used"
                    flycheck-checker))
1393 1394
    (or (flycheck-try-last-checker-for-buffer)
        (flycheck-get-new-checker-for-buffer))))
1395

1396 1397
(defun flycheck-get-next-checker-for-buffer (checker)
  "Get the checker to run after CHECKER for the current buffer."
1398 1399 1400 1401 1402
  (-when-let (next-checkers (flycheck-checker-next-checkers checker))
    (let ((next-checker (-first #'flycheck-may-use-next-checker next-checkers)))
      (if (symbolp next-checker)
          next-checker
        (cdr next-checker)))))
1403

1404 1405 1406
(defun flycheck-select-checker (checker)
  "Select CHECKER for the current buffer.

1407 1408 1409 1410
CHECKER is a syntax checker symbol (see `flycheck-checkers') or
nil.  It does not need to be registered in `flycheck-checkers'.
If nil deselect the current syntax checker (if any) and use
automatic checker selection via `flycheck-checkers'.
1411

1412 1413 1414 1415
If called interactively prompt for CHECKER.  If no syntax checker
is entered deselect the current syntax checker.  With prefix arg
immediately deselect the current syntax checker without any
prompt.
1416 1417

Set `flycheck-checker' to CHECKER and automatically start a new
1418
syntax check if the syntax checker changed."
1419 1420 1421
  (interactive
   (if current-prefix-arg
       (list nil)
1422
     (list (read-flycheck-checker "Select checker: "))))
1423 1424
  (when (not (eq checker flycheck-checker))
    (setq flycheck-checker checker)
1425 1426
    (when flycheck-mode
      (flycheck-buffer))))