config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

consult-flymake.el (4815B)


      1 ;;; consult-flymake.el --- Provides the command `consult-flymake' -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2021-2024 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 (eval-when-compile (require 'cl-lib))
     31 
     32 (defconst consult-flymake--narrow
     33   '((?e . "Error")
     34     (?w . "Warning")
     35     (?n . "Note")))
     36 
     37 (defun consult-flymake--candidates (diags)
     38   "Return Flymake errors from DIAGS as formatted candidates.
     39 DIAGS should be a list of diagnostics as returned from `flymake-diagnostics'."
     40   (let* ((diags
     41           (mapcar
     42            (lambda (diag)
     43              (let ((buffer (flymake-diagnostic-buffer diag))
     44                    (type (flymake-diagnostic-type diag)))
     45                (when (buffer-live-p buffer)
     46                  (with-current-buffer buffer
     47                    (save-excursion
     48                      (without-restriction
     49                        (goto-char (flymake-diagnostic-beg diag))
     50                        (list (buffer-name buffer)
     51                              (line-number-at-pos)
     52                              type
     53                              (flymake-diagnostic-text diag)
     54                              (point-marker)
     55                              (flymake-diagnostic-end diag)
     56                              (pcase (flymake--lookup-type-property type 'flymake-category)
     57                                ('flymake-error ?e)
     58                                ('flymake-warning ?w)
     59                                (_ ?n)))))))))
     60            diags))
     61          (diags (or (delq nil diags)
     62                     (user-error "No flymake errors (Status: %s)"
     63                                 (if (seq-difference (flymake-running-backends)
     64                                                     (flymake-reporting-backends))
     65                                     'running 'finished))))
     66          (buffer-width (cl-loop for x in diags maximize (length (nth 0 x))))
     67          (line-width (cl-loop for x in diags maximize (length (number-to-string (nth 1 x)))))
     68          (fmt (format "%%-%ds %%-%dd %%-7s %%s" buffer-width line-width)))
     69     (mapcar
     70      (pcase-lambda (`(,buffer ,line ,type ,text ,beg ,end ,narrow))
     71        (propertize (format fmt buffer line
     72                            (propertize (format "%s" (flymake--lookup-type-property
     73                                                      type 'flymake-type-name type))
     74                                        'face (flymake--lookup-type-property
     75                                               type 'mode-line-face 'flymake-error))
     76                            text)
     77                    'consult--candidate (list beg (cons 0 (- end beg)))
     78                    'consult--type narrow))
     79      ;; Sort by buffer, severity and position.
     80      (sort diags
     81            (pcase-lambda (`(,b1 _ ,t1 _ ,m1 _) `(,b2 _ ,t2 _ ,m2 _))
     82              (let ((s1 (flymake--severity t1))
     83                    (s2 (flymake--severity t2)))
     84                (or
     85                 (string-lessp b1 b2)
     86                 (and (string-equal b1 b2)
     87                      (or
     88                       (> s1 s2)
     89                       (and (= s1 s2)
     90                            (< m1 m2)))))))))))
     91 
     92 ;;;###autoload
     93 (defun consult-flymake (&optional project)
     94   "Jump to Flymake diagnostic.
     95 When PROJECT is non-nil then prompt with diagnostics from all
     96 buffers in the current project instead of just the current buffer."
     97   (interactive "P")
     98   (consult--forbid-minibuffer)
     99   (consult--read
    100    (consult-flymake--candidates
    101      (if-let ((project (and project (project-current))))
    102          (flymake--project-diagnostics project)
    103        (flymake-diagnostics)))
    104    :prompt "Flymake diagnostic: "
    105    :category 'consult-flymake-error
    106    :history t ;; disable history
    107    :require-match t
    108    :sort nil
    109    :group (consult--type-group consult-flymake--narrow)
    110    :narrow (consult--type-narrow consult-flymake--narrow)
    111    :lookup #'consult--lookup-candidate
    112    :state (consult--jump-state)))
    113 
    114 (provide 'consult-flymake)
    115 ;;; consult-flymake.el ends here