blob: 2ecf61e336c49b4352e15e7e9e2de5da2ae4f238 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
;;; flymake-clippy.el --- Flymake backend for Clippy -*- lexical-binding: t; -*-
;; Copyright (C) 2023 Graham Marlow
;; Author: Graham Marlow <info@mgmarlow.com>
;; Keywords: tools
;; URL: https://sr.ht/~mgmarlow/flymake-clippy/
;; Version: 1.0.0
;; Package-Requires: ((emacs "26.1"))
;; 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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Flymake backend for Clippy, the Rust linter.
;; https://doc.rust-lang.org/stable/clippy/index.html
;;; Code:
(require 'cl-lib)
;; Capture group source example:
;; "warning: ..."
;; --> src/filename.rs
;; 98 | ...
(defun flymake-clippy--build-regexp ()
"Regexp for Clippy output."
(rx (seq line-start
;; Message
(group (or "warning:" "error:")
(zero-or-more nonl))
"\n"
(zero-or-more nonl)
"--> "
;; File
(group
(zero-or-more nonl))
":"
;; Line
(group
(one-or-more
(any "0-9")))
":"
;; Col
(group
(one-or-more
(any "0-9")))
line-end)))
(defvar-local flymake-clippy--proc nil
"Clippy subprocess object, used to ensure obsolete processes aren't reused.")
(defun flymake-clippy-backend (report-fn &rest _args)
"Flymake backend for Clippy, the Rust linter.
Calls REPORT-FN with a list of Flymake diagnostics for the
current buffer.
Use `flymake-clippy-setup-backend' to register the backend
with the appropriate Flymake hook."
(unless (executable-find "cargo")
(error "Cannot find cargo"))
(let* ((source (current-buffer))
(filename (buffer-file-name source)))
(save-restriction
(widen)
(setq flymake-clippy--proc
(make-process
:name "flymake-clippy" :noquery t :connection-type 'pipe
:buffer (generate-new-buffer "*flymake-clippy*")
:command '("cargo" "clippy")
:sentinel
(lambda (proc _event)
(when (memq (process-status proc) '(exit signal))
(unwind-protect
(if (with-current-buffer source (eq proc flymake-clippy--proc))
(with-current-buffer (process-buffer proc)
(goto-char (point-min))
;; Collect output buffer into diagnostic messages/locations,
;; exposing them via `report-fn'.
(cl-loop
while (search-forward-regexp
(flymake-clippy--build-regexp)
nil t)
for msg = (match-string 1)
for sourcefile = (match-string 2)
for (beg . end) = (flymake-diag-region
source
(string-to-number (match-string 3)))
for type = (if (string-match "^warning" msg)
:warning
:error)
when (and sourcefile (string-match-p sourcefile filename))
collect (flymake-make-diagnostic source beg end type msg)
into diags
finally (funcall report-fn diags)))
(flymake-log :warning "Canceling obsolete check %s" proc))
;; Cleanup temp buffer.
(kill-buffer (process-buffer proc)))))))
(process-send-region flymake-clippy--proc (point-min) (point-max))
(process-send-eof flymake-clippy--proc))))
(defun flymake-clippy-setup-backend ()
"Add `flymake-clippy' to `flymake-diagnostic-functions' hook."
(add-hook 'flymake-diagnostic-functions #'flymake-clippy-backend nil t))
(provide 'flymake-clippy)
;;; flymake-clippy.el ends here
|