flycheck / flycheck-inline

Display Flycheck errors inline

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is it possible to display all of these inline at once?

i-am-the-slime opened this issue · comments

That's what I expected by the name of this library. And that's what the last screenshot looks like. However I still need to have my (evil) cursor over the problematic part of the code to display the flycheck message.

In the last screenshot, there is at least one error that is not displayed. What flycheck-inline currently does is to display related errors. These are errors that are from the same diagnostic for the rustc compiler for instance.

Do you want all the errors of the buffer to be displayed at once? And do you want them to display when you put your cursor on any one of them, or right after a check?

Both should be possible, although I'm not sure about the usability.

I would like to see the errors all at once, right after the check.
This way I save some time by not having to go to "next error" or "previous error".
Sometimes I don't want to solve the problems linearly anyway, so I have to do this go to next go to previous linearly until I get to the error I care about.
Maybe it could be toggled?

Maybe it could be toggled?

Yes, I think we can make that an option without too much hassle. The code for displaying the errors inline should be able to handle that, though currently we hook into flycheck-display-errors-function which gives us the errors at point, we can look into flycheck-current-errors to get all of them and use that instead.

Not a high priority for me to carry that PR though, so if you want to lend a hand, go ahead.

commented

+1, i think this would be a nice feature to have.
I was also looking for something that would show flycheck errors automatically as im typing code, without the need to focus on the symbol / save the file.

+1, also would like this feature. Any pointers on moving this in a certain direction? How would one hook into flycheck-current-errors in a way that informs flycheck-inline to display all errors? I've tried naively evaluation (flycheck-inline-display-errors flycheck-current-errors) in an elisp buffer with visible errors but to no avail.

I want to use such a feature, too. Has anyone found any package implementing it? If not, I considered forking this package and finding which parts of the code need to be adjusted to have the behavior this issue proposes.

After doing some searching, you may be interested in this here https://github.com/emacs-sideline.

+1

For anyone who wants it, I implemented it myself:

;;; fia.el --- Display Flycheck errors inline -*- lexical-binding: t; -*-
;; Copyright (C) 2017-2018 fmdkdd

;; Author: fmdkdd
;; URL: https://github.com/flycheck/flycheck-inline
;; Keywords: tools, convenience
;; Version: 0.1-cvs
;; Package-Requires: ((emacs "25.1") (flycheck "32"))

;; 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 <http://www.gnu.org/licenses/>.

;;; Commentary:

;; Provide an error display function to show Flycheck errors inline, directly
;; below their location in the buffer.
;;
;; # Setup
;;
;; Enable the local minor mode for all flycheck-mode buffers:
;;
;; (with-eval-after-load 'flycheck
;;   (add-hook 'flycheck-mode-hook #'fia-mode))

;;; Code:

(require 'flycheck)
(require 'seq)

;;; Displaying line-long overlays (phantoms)

(defun fia-phantom-display (msg &optional pos err)
  "Display MSG in a phantom directly below POS.

MSG is a string that will be put in a line-long overlay (phantom)
at the line immediately following POS.  If POS is nil, current
point is used instead.

Return the displayed phantom."
  (pcase-let* ((p (or pos (point)))
               (`(,offset . ,pos-eol)
                (save-excursion
                  (goto-char p)
                  (cons (- p (point-at-bol)) (point-at-eol))))
               (ov (make-overlay pos-eol (1+ pos-eol)))
               ;; If the error is on the last line, and that line doesn't end
               ;; with a newline, the overlay will be displayed at the end of
               ;; the line instead of below it.  Adding a newline before the
               ;; message fixes it.
               (str (concat (when (eq pos-eol (point-max)) "\n")
                            (fia-indent-message offset msg)
                            "\n")))
    (overlay-put ov 'phantom t)
    (overlay-put ov 'after-string str)
    (overlay-put ov 'error err)
    ov))

(defun fia--contains-point (phantom &optional pt)
  "Whether the given error overlay contains the position PT otherwise `(point)'"
  (let* ((pos (or pt (point)))
         (err (overlay-get phantom 'error))
         (region (flycheck-error-region-for-mode err 'symbols)))
    (and phantom
         ;; Must be one of our phantoms (probably unneeded).
         (overlay-get phantom 'phantom)
         ;; The underlying error must currently exist.
         err
         (memq err flycheck-current-errors)
         ;; Most importantly, point must be within the error bounds.
         region
         (>= pos (car region))
         (<= pos (cdr region)))))

(defun fia-phantom-delete (phantom)
  "Delete PHANTOM if its region doesn't contain point.

Returns the overlay removed or nil."
  (if (fia--contains-point phantom)
      nil
    (progn (delete-overlay phantom) t)))

(defun fia-indent-message (offset msg)
  "Indent all lines of MSG by OFFSET spaces.

MSG is trimmed beforehand."
  (let* ((pad (make-string offset ?\s))
         (rep (concat "\n" pad)))
    (concat pad
            (replace-regexp-in-string "\n" rep (string-trim msg)))))


;;; Customization

(defgroup fia nil
  "Display Flycheck errors inline."
  :prefix "fia-"
  :group 'flycheck
  :link '(url-link :tag "Github" "https://github.com/flycheck/fia"))

(defface fia-error
  '((t :inherit compilation-error))
  "fia face for errors."
  :package-version '(fia . "0.1")
  :group 'fia)

(defface fia-warning
  '((t :inherit compilation-warning))
  "fia face for warnings."
  :package-version '(fia . "0.1")
  :group 'fia)

(defface fia-info
  '((t :inherit compilation-info))
  "fia face for informational messages."
  :package-version '(fia . "0.1")
  :group 'fia)

(defcustom fia-display-function #'fia-display-phantom
  "Function to display inline errors.

This function is used to display inline all errors at point, as
well as all related errors.  It has the signature (MSG &optional
POS ERR), where MSG is the error message to display, POS its
buffer position, and ERR is the flycheck error in general."
  :group 'fia
  :package-version '(fia . "0.1")
  :type '(function :tag "Inline error display function")
  :risky t)

(defcustom fia-clear-function #'fia-clear-phantoms
  "Function to clear all inline errors.

It takes no arguments and should remove all inline errors created
by `fia-display-function'."
  :group 'fia
  :package-version '(fia . "0.1")
  :type '(function :tag "Inline error clear function")
  :risky t)

(defcustom fia-display-error-id t
  "Whether to display error IDs inline.

If non-nil, inline errors will contain the error ID.  Error IDs
are optional: not all checkers suplpy this information.  Error
IDs can also be seen in Flycheck's error list."
  :group 'fia
  :type 'boolean
  :package-version '(fia . "0.1")
  :safe #'booleanp)

;;; Displaying inline errors with phantoms

(defun fia--displayed-p (err)
  "Whether the given error is displayed with any inline overlays."
  (seq-find (lambda (p) (eq err (overlay-get p 'error)))
            fia--phantoms))

(defvar-local fia--phantoms nil
  "Remember which phantoms were added to the buffer.")

(defun fia-display-phantom (msg &optional pos err)
  "Display MSG at POS representing error ERR using phantoms.

POS defaults to point."
  (unless (fia--displayed-p err)
    (push (fia-phantom-display msg pos err) fia--phantoms)))

(defun fia-clear-phantoms ()
  "Remove all phantoms from buffer that don't contain point."
  (setq fia--phantoms
        (seq-remove #'fia-phantom-delete fia--phantoms)))


;;; Display inline errors

(defun fia--error-position (err)
  "Return the position to insert ERR at."
  (if (flycheck-relevant-error-other-file-p err)
      ;; Display overlays for other-file errors on the first line
      (point-min)
    (flycheck-error-pos err)))

(defun fia--error-message (err)
  "Return the message to display for ERR."
  (let ((filename (flycheck-error-filename err))
        (id (flycheck-error-id 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 (and id fia-display-error-id)
              (format " [%s]" id)))))

(defun fia--error-face (err)
  "Return the face used to display ERR."
  (pcase (flycheck-error-level err)
    (`info 'fia-info)
    (`warning 'fia-warning)
    (`error 'fia-error)))

(defun fia-display-error (err)
  "Display `flycheck-error' ERR inline."
  (let* ((pos (fia--error-position err))
         (msg (propertize (fia--error-message err)
                          'face (fia--error-face err))))
    (funcall fia-display-function msg pos err)))

(defun fia-hide-errors ()
  "Hide all inline messages currently being shown."
  (funcall fia-clear-function))

(defun fia-display-errors-all ()
  (fia-display-errors flycheck-current-errors))

(defun fia-display-errors (errors)
  "Display ERRORS, and all related errors, inline.

ERRORS is a list of `flycheck-error' objects."
  (fia-hide-errors)
  (mapc #'fia-display-error
        (seq-uniq
         (seq-mapcat #'flycheck-related-errors errors))))

;;; Global and local minor modes

;;;###autoload
(define-minor-mode fia-mode
  "A minor mode to show Flycheck error messages line.

When called interactively, toggle `fia-mode'.  With
prefix ARG, enable `fia-mode' if ARG is positive,
otherwise disable it.

When called from Lisp, enable `fia-mode' if ARG is
omitted, nil or positive.  If ARG is `toggle', toggle
`fia-mode'.  Otherwise behave as if called
interactively.

In `fia-mode', show Flycheck error messages inline,
directly below the error reported location."
  :group 'fia
  :require 'fia
  (cond
   ;; Use our display function.
   (fia-mode
    (add-hook 'flycheck-after-syntax-check-hook #'fia-display-errors-all nil 'local))
   ;; Reset the display function and remove ourselves from all hooks but only
   ;; if the mode is still active.
   ((not fia-mode)
    (fia-hide-errors)
    (add-hook 'flycheck-after-syntax-check-hook #'fia-display-errors-all nil 'local))))

(defun turn-on-fia ()
  "Turn on `fia-mode' in Flycheck buffers."
  ;; Make sure to turn on fia in this buffer, either directly if
  ;; flycheck is already loaded, or via a hook if flycheck hasn't been loaded
  ;; yet.
  (if flycheck-mode
      (fia-mode)
    (add-hook 'flycheck-mode-hook #'fia-mode nil 'local)))

;;;###autoload
(define-global-minor-mode global-fia-mode
  fia-mode turn-on-fia
  "Toggle fia in all Flycheck buffers."
  :group 'fia
  :require 'fia)

(provide 'fia)
;;; fia.el ends here

Maybe someone wants to patch the current mode to enable toggling, but this is all I wanted so it's hacked.

Does this:

image