emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] emacs-26 483f1e8 22/39: A couple of Flymake backends for e


From: João Távora
Subject: [Emacs-diffs] emacs-26 483f1e8 22/39: A couple of Flymake backends for emacs-lisp-mode
Date: Tue, 3 Oct 2017 10:04:51 -0400 (EDT)

branch: emacs-26
commit 483f1e834d9008e7b48d7abb3afa84be352014b1
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>

    A couple of Flymake backends for emacs-lisp-mode
    
    Loading flymake-elisp.el doesn't setup flymake-mode to turn on
    automatically, but it affects emacs-lisp-mode-hook so that
    flymake-diagnostic-functions is setup with a suitable buffer-local
    value.  The variable flymake-diagnostic-funtions in every live
    emacs-lisp-mode buffer is also adjusted.
    
    * lisp/progmodes/flymake.el (top): Require flymake-elisp.
    
    * lisp/progmodes/flymake-elisp.el: New file.
---
 lisp/progmodes/flymake-elisp.el | 176 ++++++++++++++++++++++++++++++++++++++++
 lisp/progmodes/flymake.el       |  12 ++-
 2 files changed, 185 insertions(+), 3 deletions(-)

diff --git a/lisp/progmodes/flymake-elisp.el b/lisp/progmodes/flymake-elisp.el
new file mode 100644
index 0000000..bf60f57
--- /dev/null
+++ b/lisp/progmodes/flymake-elisp.el
@@ -0,0 +1,176 @@
+;;; flymake-elisp.el --- Flymake backends for emacs-lisp-mode  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2017  João Távora
+
+;; Author: João Távora <address@hidden>
+;; Keywords:
+
+;; 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:
+
+;; Flymake backends for elisp work.
+
+;;; Code:
+(require 'flymake)
+(require 'checkdoc)
+(eval-when-compile (require 'cl-lib))
+(require 'bytecomp)
+
+(defun flymake-elisp--checkdoc-1 ()
+  "Do actual work for `flymake-elisp-checkdoc'."
+  (let (collected)
+    (cl-letf (((symbol-function 'checkdoc-create-error)
+               (lambda (text start end &optional unfixable)
+                 (push (list text start end unfixable) collected)
+                 nil)))
+      (let* ((checkdoc-autofix-flag nil)
+             (checkdoc-generate-compile-warnings-flag nil)
+             (buf (generate-new-buffer " *checkdoc-temp*"))
+             (checkdoc-diagnostic-buffer buf))
+        (unwind-protect
+            (save-excursion
+              (checkdoc-current-buffer t))
+          (kill-buffer buf))))
+    collected))
+
+(defun flymake-elisp-checkdoc (report-fn)
+  "A flymake backend for `checkdoc'.
+Calls REPORT-FN directly."
+  (when (derived-mode-p 'emacs-lisp-mode)
+    (funcall report-fn
+             (cl-loop for (text start end _unfixable) in
+                      (flymake-elisp--checkdoc-1)
+                      collect
+                      (flymake-make-diagnostic
+                       (current-buffer)
+                       start end :note text)))))
+
+(defun flymake-elisp--byte-compile-done (report-fn
+                                         origin-buffer
+                                         output-buffer
+                                         temp-file)
+  (unwind-protect
+      (with-current-buffer
+          origin-buffer
+        (save-excursion
+          (save-restriction
+            (widen)
+            (funcall
+             report-fn
+             (ignore-errors
+               (cl-loop with data =
+                        (with-current-buffer output-buffer
+                          (goto-char (point-min))
+                          (search-forward ":flymake-elisp-output-start")
+                          (read (point-marker)))
+                        for (string pos _fill level) in data
+                        do (goto-char pos)
+                        for beg = (if (< (point) (point-max))
+                                      (point)
+                                    (line-beginning-position))
+                        for end = (min
+                                   (line-end-position)
+                                   (or (cdr
+                                        (bounds-of-thing-at-point 'sexp))
+                                       (point-max)))
+                        collect (flymake-make-diagnostic
+                                 (current-buffer)
+                                 (if (= beg end) (1- beg) beg)
+                                 end
+                                 level
+                                 string)))))))
+    (kill-buffer output-buffer)
+    (ignore-errors (delete-file temp-file))))
+
+(defun flymake-elisp-byte-compile (report-fn)
+  "A flymake backend for elisp byte compilation.
+Spawn an Emacs process that byte-compiles a file representing the
+current buffer state and calls REPORT-FN when done."
+  (interactive (list (lambda (stuff)
+                       (message "aha %s" stuff))))
+  (when (derived-mode-p 'emacs-lisp-mode)
+    (let ((temp-file (make-temp-file "flymake-elisp-byte-compile"))
+          (origin-buffer (current-buffer)))
+      (save-restriction
+        (widen)
+        (write-region (point-min) (point-max) temp-file nil 'nomessage))
+      (let* ((output-buffer (generate-new-buffer " 
*flymake-elisp-byte-compile*")))
+        (make-process
+         :name "flymake-elisp-byte-compile"
+         :buffer output-buffer
+         :command (list (expand-file-name invocation-name invocation-directory)
+                        "-Q"
+                        "--batch"
+                        ;; "--eval" "(setq load-prefer-newer t)" ; for testing
+                        "-L" default-directory
+                        "-l" "flymake-elisp"
+                        "-f" "flymake-elisp--batch-byte-compile"
+                        temp-file)
+         :connection-type 'pipe
+         :sentinel
+         (lambda (proc _event)
+           (unless (process-live-p proc)
+             (flymake-elisp--byte-compile-done report-fn
+                                               origin-buffer
+                                               output-buffer
+                                               temp-file))))
+        :stderr null-device
+        :noquery t))))
+
+(defun flymake-elisp--batch-byte-compile (&optional file)
+  "Helper for `flymake-elisp-byte-compile'.
+Runs in a batch-mode Emacs.  Interactively use variable
+`buffer-file-name' for FILE."
+  (interactive (list buffer-file-name))
+  (let* ((file (or file
+                   (car command-line-args-left)))
+         (dummy-elc-file)
+         (byte-compile-log-buffer
+          (generate-new-buffer " *dummy-byte-compile-log-buffer*"))
+         (byte-compile-dest-file-function
+          (lambda (source)
+            (setq dummy-elc-file (make-temp-file (file-name-nondirectory 
source)))))
+         (collected))
+    (unwind-protect
+        (cl-letf (((symbol-function 'byte-compile-log-warning)
+                   (lambda (string &optional fill level)
+                     (push (list string byte-compile-last-position fill level)
+                           collected)
+                     t)))
+          (byte-compile-file file))
+      (ignore-errors
+        (delete-file dummy-elc-file)
+        (kill-buffer byte-compile-log-buffer)))
+    (prin1 :flymake-elisp-output-start)
+    (terpri)
+    (pp collected)))
+
+(defun flymake-elisp-setup-backends ()
+  "Setup flymake for elisp work."
+  (add-to-list (make-local-variable 'flymake-diagnostic-functions)
+               'flymake-elisp-checkdoc t)
+  (add-to-list (make-local-variable 'flymake-diagnostic-functions)
+               'flymake-elisp-byte-compile t))
+
+(add-hook 'emacs-lisp-mode-hook
+          'flymake-elisp-setup-backends)
+
+(dolist (buffer (buffer-list))
+  (with-current-buffer buffer
+    (when (derived-mode-p 'emacs-lisp-mode)
+      (flymake-elisp-setup-backends))))
+
+(provide 'flymake-elisp)
+;;; flymake-elisp.el ends here
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 03b319f..8c92dc7 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -526,10 +526,15 @@ A backend is disabled if it reported `:panic'.")
   (flymake-log :warning "Disabled the backend %s due to reports of %s (%s)"
                backend action explanation))
 
-(cl-defun flymake--handle-report (backend action &key explanation)
-  "Handle reports from flymake backend identified by BACKEND."
+(cl-defun flymake--handle-report (backend action &key explanation force)
+  "Handle reports from flymake backend identified by BACKEND.
+
+BACKEND, ACTION and EXPLANATION conform to the calling convention
+described in `flymake-diagnostic-functions' (which see). Optional
+FORCE says to handle a report even if it was not expected."
   (cond
-   ((not (memq backend flymake--running-backends))
+   ((and (not (memq backend flymake--running-backends))
+         (not force))
     (flymake-error "Ignoring unexpected report from backend %s" backend))
    ((eq action :progress)
     (flymake-log 3 "Backend %s reports progress: %s" backend explanation))
@@ -851,4 +856,5 @@ diagnostics of type `:error' and `:warning'."
 (provide 'flymake)
 
 (require 'flymake-proc)
+(require 'flymake-elisp)
 ;;; flymake.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]