dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

consult-flymake.el (4841B)


      1 ;;; consult-flymake.el --- Provides the command `consult-flymake' -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
      4 
      5 ;; This file is part of GNU Emacs.
      6 
      7 ;; This program is free software: you can redistribute it and/or modify
      8 ;; it under the terms of the GNU General Public License as published by
      9 ;; the Free Software Foundation, either version 3 of the License, or
     10 ;; (at your option) any later version.
     11 
     12 ;; This program is distributed in the hope that it will be useful,
     13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 ;; GNU General Public License for more details.
     16 
     17 ;; You should have received a copy of the GNU General Public License
     18 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     19 
     20 ;;; Commentary:
     21 
     22 ;; Provides the command `consult-flymake'.  This is an extra package,
     23 ;; to allow lazy loading of flymake.el.  The `consult-flymake' command
     24 ;; is autoloaded.
     25 
     26 ;;; Code:
     27 
     28 (require 'consult)
     29 (require 'flymake)
     30 
     31 (defconst consult-flymake--narrow
     32   '((?e . "Error")
     33     (?w . "Warning")
     34     (?n . "Note")))
     35 
     36 (defun consult-flymake--candidates (diags)
     37   "Return Flymake errors from DIAGS as formatted candidates.
     38 DIAGS should be a list of diagnostics as returned from `flymake-diagnostics'."
     39   (let* ((diags
     40           (mapcar
     41            (lambda (diag)
     42              (let ((buffer (flymake-diagnostic-buffer diag))
     43                    (type (flymake-diagnostic-type diag)))
     44                (with-current-buffer buffer
     45                  (save-excursion
     46                    (save-restriction
     47                      (widen)
     48                      (goto-char (flymake-diagnostic-beg diag))
     49                      (list (buffer-name buffer)
     50                            (line-number-at-pos)
     51                            type
     52                            (flymake-diagnostic-text diag)
     53                            (point-marker)
     54                            (flymake-diagnostic-end diag)
     55                            (pcase (flymake--lookup-type-property type 'flymake-category)
     56                               ('flymake-error ?e)
     57                               ('flymake-warning ?w)
     58                               (_ ?n))))))))
     59            (seq-filter (lambda (diag)
     60                          (buffer-live-p (flymake-diagnostic-buffer diag)))
     61                        diags)))
     62          (buffer-width (apply #'max (mapcar (lambda (x) (length (nth 0 x))) diags)))
     63          (line-width (apply #'max (mapcar (lambda (x) (length (number-to-string (nth 1 x)))) diags)))
     64          (fmt (format "%%-%ds %%-%dd %%-7s %%s" buffer-width line-width)))
     65     (mapcar
     66      (pcase-lambda (`(,buffer ,line ,type ,text ,beg ,end ,narrow))
     67        (propertize (format fmt buffer line
     68                            (propertize (format "%s" (flymake--lookup-type-property
     69                                                      type 'flymake-type-name type))
     70                                        'face (flymake--lookup-type-property
     71                                               type 'mode-line-face 'flymake-error))
     72                            text)
     73                    'consult--candidate (list beg (cons 0 (- end beg)))
     74                    'consult--type narrow))
     75      ;; Sort by buffer, severity and position.
     76      (sort diags
     77            (pcase-lambda (`(,b1 _ ,t1 _ ,m1 _) `(,b2 _ ,t2 _ ,m2 _))
     78              (let ((s1 (flymake--severity t1))
     79                    (s2 (flymake--severity t2)))
     80                (or
     81                 (string-lessp b1 b2)
     82                 (and (string-equal b1 b2)
     83                      (or
     84                       (> s1 s2)
     85                       (and (= s1 s2)
     86                            (< m1 m2)))))))))))
     87 
     88 ;;;###autoload
     89 (defun consult-flymake (&optional project)
     90   "Jump to Flymake diagnostic.
     91 When PROJECT is non-nil then prompt with diagnostics from all
     92 buffers in the current project instead of just the current buffer."
     93   (interactive "P")
     94   (consult--forbid-minibuffer)
     95   (consult--read
     96    (consult-flymake--candidates
     97     (or
     98      (if-let (((and project (fboundp 'flymake--project-diagnostics)))
     99               (project (project-current)))
    100          (flymake--project-diagnostics project)
    101        (flymake-diagnostics))
    102      (user-error "No flymake errors (Status: %s)"
    103                  (if (seq-difference (flymake-running-backends)
    104                                      (flymake-reporting-backends))
    105                      'running 'finished))))
    106    :prompt "Flymake diagnostic: "
    107    :category 'consult-flymake-error
    108    :history t ;; disable history
    109    :require-match t
    110    :sort nil
    111    :group (consult--type-group consult-flymake--narrow)
    112    :narrow (consult--type-narrow consult-flymake--narrow)
    113    :lookup #'consult--lookup-candidate
    114    :state (consult--jump-state)))
    115 
    116 (provide 'consult-flymake)
    117 ;;; consult-flymake.el ends here