my-emacs-d/elpa/helm-flycheck-20160710.129/helm-flycheck.el

198 lines
7.3 KiB
EmacsLisp

;;; helm-flycheck.el --- Show flycheck errors with helm
;; Copyright (C) 2013-2016 Yasuyuki Oka <yasuyk@gmail.com>
;; Author: Yasuyuki Oka <yasuyk@gmail.com>
;; Version: 0.4
;; Package-Version: 20160710.129
;; URL: https://github.com/yasuyk/helm-flycheck
;; Package-Requires: ((dash "2.12.1") (flycheck "28") (helm-core "1.9.8"))
;; Keywords: helm, flycheck
;; 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/>.
;;; Commentary:
;; Installation:
;; Add the following to your Emacs init file:
;;
;; (require 'helm-flycheck) ;; Not necessary if using ELPA package
;; (eval-after-load 'flycheck
;; '(define-key flycheck-mode-map (kbd "C-c ! h") 'helm-flycheck))
;; That's all.
;;; Code:
(require 'dash)
(require 'flycheck)
(require 'helm)
(defvar helm-source-flycheck
'((name . "Flycheck")
(init . helm-flycheck-init)
(candidates . helm-flycheck-candidates)
(action-transformer helm-flycheck-action-transformer)
(multiline)
(action . (("Go to" . helm-flycheck-action-goto-error)))
(follow . 1)))
(defvar helm-flycheck-candidates nil)
(defconst helm-flycheck-status-message-no-errors
"There are no errors in the current buffer.")
(defconst helm-flycheck-status-message-syntax-checking
"Syntax checking now. Do action to reexecute `helm-flycheck'.")
(defconst helm-flycheck-status-message-checker-not-found
"A suitable syntax checker is not found. \
See Selection in flycheck manual, for more information.")
(defconst helm-flycheck-status-message-failed
"The syntax check failed. Inspect the *Messages* buffer for details.")
(defconst helm-flycheck-status-message-dubious
"The syntax check had a dubious result. \
Inspect the *Messages* buffer for details.")
(defun helm-flycheck-init ()
"Initialize `helm-source-flycheck'."
(setq helm-flycheck-candidates
(if (flycheck-has-current-errors-p)
(mapcar 'helm-flycheck-make-candidate
(sort flycheck-current-errors #'flycheck-error-<))
(list (helm-flycheck-status-message)))))
(defun helm-flycheck-status-message ()
"Return message about `flycheck' STATUS."
(cond ((equal flycheck-last-status-change 'finished)
helm-flycheck-status-message-no-errors)
((equal flycheck-last-status-change 'running)
helm-flycheck-status-message-syntax-checking)
((equal flycheck-last-status-change 'no-checker)
helm-flycheck-status-message-checker-not-found)
((equal flycheck-last-status-change 'errored)
helm-flycheck-status-message-failed)
((equal flycheck-last-status-change 'suspicious)
helm-flycheck-status-message-dubious)))
(defun helm-flycheck-make-candidate (error)
"Return a cons constructed from string of message and ERROR."
(cons (helm-flycheck-candidate-display-string error) error))
(defun helm-flycheck-candidate-display-string (error)
"Return a string of message constructed from ERROR."
(let ((face (-> error
flycheck-error-level
flycheck-error-level-error-list-face)))
(format "%5s %3s%8s %s"
(propertize (number-to-string (flycheck-error-line error)) 'font-lock-face 'flycheck-error-list-line-number)
(-if-let (column (flycheck-error-column error))
(propertize (number-to-string column) 'font-lock-face 'flycheck-error-list-column-number) "")
(propertize (symbol-name (flycheck-error-level error))
'font-lock-face face)
(or (flycheck-error-message error) ""))))
(defun helm-flycheck-action-transformer (actions candidate)
"Return modified ACTIONS if CANDIDATE is status message."
(if (stringp candidate)
(cond ((string= candidate helm-flycheck-status-message-no-errors) nil)
((string= candidate helm-flycheck-status-message-syntax-checking)
'(("Reexecute helm-flycheck" . helm-flycheck-action-reexecute)))
((string= candidate helm-flycheck-status-message-checker-not-found)
'(("Enter info of Syntax checker selection" .
helm-flycheck-action-selection-info)))
((or (string= candidate helm-flycheck-status-message-failed)
(string= candidate helm-flycheck-status-message-dubious))
'(("Switch to *Messages*" .
helm-flycheck-action-switch-to-messages-buffer))))
actions))
(defun helm-flycheck-action-goto-error (candidate)
"Visit error of CANDIDATE."
(let ((buffer (flycheck-error-buffer candidate))
(lineno (flycheck-error-line candidate))
error-pos)
(with-current-buffer buffer
(switch-to-buffer buffer)
(goto-char (point-min))
(forward-line (1- lineno))
(setq error-pos
(car
(->> (flycheck-overlays-in
(point)
(save-excursion (forward-line 1) (point)))
(-map #'overlay-start)
-uniq
(-sort #'<=))))
(goto-char error-pos)
(let ((recenter-redisplay nil))
(recenter)))))
(defun helm-flycheck-action-reexecute (candidate)
"Reexecute `helm-flycheck' without CANDIDATE."
(catch 'exit
(helm-run-after-exit 'helm-flycheck)))
(defun helm-flycheck-action-switch-to-messages-buffer (candidate)
"Switch to *Messages* buffer without CANDIDATE."
(switch-to-buffer "*Messages*"))
(defun helm-flycheck-action-selection-info (candidate)
"Enter info of flycheck syntax checker selection without CANDIDATE."
(info "(flycheck)Top > Usage > Selection"))
(defun helm-flycheck-preselect ()
"PreSelect nearest error from the current point."
(let* ((point (point))
(overlays-at-point (flycheck-overlays-at point))
candidates nearest-point)
(if overlays-at-point
(helm-flycheck-candidate-display-string
(car (flycheck-overlay-errors-at point)))
(setq candidates (->> (flycheck-overlays-in (point-min) (point-max))
(-map #'overlay-start)
-uniq))
(setq nearest-point (helm-flycheck-nearest-point point candidates))
(when nearest-point
(helm-flycheck-candidate-display-string
(car (flycheck-overlay-errors-at nearest-point)))))))
(defun helm-flycheck-nearest-point (current-point points)
"Return nearest point from CURRENT-POINT in POINTS."
(--tree-reduce-from
(if (< (abs (- current-point it)) (abs (- current-point acc)))
it acc) (car points) points))
;;;###autoload
(defun helm-flycheck ()
"Show flycheck errors with `helm'."
(interactive)
(unless flycheck-mode
(user-error "Flycheck mode not enabled"))
(helm :sources 'helm-source-flycheck
:buffer "*helm flycheck*"
:preselect (helm-flycheck-preselect)))
(provide 'helm-flycheck)
;; Local Variables:
;; coding: utf-8
;; End:
;;; helm-flycheck.el ends here