Subject: bug#52342: [PATCH] Add Texinfo support for Flymake

From: Okamsn <[email-masked]>
Date: Sun, 19 Dec 2021 16:17:56 +0000

On 12/7/21 18:46, João Távora wrote:
> On Tue, Dec 7, 2021 at 11:43 PM João Távora <[email-masked]
> <mailto:[email-masked]>> wrote:
>
>
>     On Tue, Dec 7, 2021 at 11:39 PM Okamsn <[email-masked]
>     <mailto:[email-masked]>> wrote:
>
>         On 12/7/21 09:23, João Távora wrote:
>          > Not sure about the eval-when-compile for require.  It was my
>          > expression that require is always "when compile".
>          >
>          > I've unfortunately been a little away from Emacs lately.
>          >
>          > João
>
>         My understanding is that `eval-when-compile` is used to make
>         sure that
>         macro definitions are available during compilation and that the
>         libraries are not loaded when `texinfo.el` is loaded.  The
>         macros in the
>         patch are `rx`, `cl-loop`, and `flymake-log`.
>
>
>     require is always `eval-and-compile` (sorry if I misled you earlier).
>     It's OK to use `eval-when-compile` when needing `cl-loop` from `cl-lib`
>     if _all_ you need form `cl-lib` is indeed macros.
>
>     But for flymake, you need the actual runtime things too, right? So
>     I think plain require is better and simpler
>
>
> Hmmm, on second thought, it you're planning on relying on
> autoloads for ultimate loading lazyness.... Hmm, maybe
> you're right...
>
> João

Hello Stefan Monnier,

Do you have any thoughts about the lazy loading of Flymake features used
in the patch discussed in this thread (re-attached for convenience)?

Thank you.

From 2209e84f98d75eb3db5589bfe6c64ded266c67e2 Mon Sep 17 00:00:00 2001
From: Earl Hyatt <[email-masked]>
Date: Mon, 6 Dec 2021 21:04:27 -0500
Subject: [PATCH v2] Add basic Texinfo support for Flymake.

* lisp/textmodes/texinfo.el (texinfo-flymake, texinfo--flymake-proc)
(texinfo-mode):
Add the functions texinfo-flymake and process variable
texinfo--flymake-proc.  Modify texinfo-mode to automatically add this
function to the hook flymake-diagnostic-functions.
---
 lisp/textmodes/texinfo.el | 78 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/lisp/textmodes/texinfo.el b/lisp/textmodes/texinfo.el
index 71db33bae3..292d819dc2 100644
--- a/lisp/textmodes/texinfo.el
+++ b/lisp/textmodes/texinfo.el
@@ -32,6 +32,16 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib)
+                   (require 'flymake)
+                   (require 'rx))
+(declare-function flymake-diag-region "flymake"
+                  (buffer line &optional col))
+(declare-function flymake-make-diagnostic "flymake"
+                  ( locus beg end type text
+                    &optional data overlay-properties))
+(declare-function flymake--log-1 (level sublog msg &rest args))
+
 (eval-when-compile (require 'tex-mode))
 (declare-function tex-buffer "tex-mode" ())
 (declare-function tex-region "tex-mode" (beg end))
@@ -336,6 +346,69 @@ texinfo-current-defun-name
     (if (re-search-backward "^@node[ \t]+\\([^,\n]+\\)" nil t)
 	(match-string-no-properties 1))))
 
+;;; Flymake support
+(defvar-local texinfo--flymake-proc nil)
+(defun texinfo-flymake (report-fn &rest _)
+  "Texinfo checking for Flymake.
+
+REPORT-FN is the callback function."
+  (let ((executable (or (executable-find "makeinfo")
+                        (executable-find "texi2any")))
+        (source (current-buffer)))
+
+    (unless executable
+      (error "Flymake for Texinfo requires `makeinfo' or `texi2any'"))
+
+    (when (process-live-p texinfo--flymake-proc)
+      (kill-process texinfo--flymake-proc))
+
+    (save-restriction
+      (widen)
+      (setq texinfo--flymake-proc
+            (make-process
+             :name "texinfo-flymake"
+             :noquery t
+             :connection-type 'pipe
+             :buffer (generate-new-buffer " *texinfo-flymake*")
+             :command `(,executable "-o" ,null-device "-")
+             :sentinel
+             (lambda (proc _event)
+               (when (memq (process-status proc) '(exit signal))
+                 (unwind-protect
+                     (if (eq (buffer-local-value 'texinfo--flymake-proc
+                                                 source)
+                             proc)
+                         (with-current-buffer (process-buffer proc)
+                           (goto-char (point-min))
+                           (cl-loop
+                            while (search-forward-regexp
+                                   (rx line-start
+                                       "-:"
+                                       (group-n 1 (0+ digit)) ; Line
+                                       (optional ":" (group-n 2 (0+ digit))) ; col
+                                       ": "
+                                       (optional (group-n 3 "warning: ")) ; warn
+                                       (group-n 4 (0+ nonl)) ; Message
+                                       line-end)
+                                   nil t)
+                            for msg = (match-string 4)
+                            for (beg . end) = (flymake-diag-region
+                                               source
+                                               (string-to-number (match-string 1)))
+                            for type = (if (match-string 3)
+                                           :warning
+                                         :error)
+                            collect (flymake-make-diagnostic
+                                     source beg end type msg)
+                            into diags
+                            finally (funcall report-fn diags)))
+                       (flymake-log :warning "Cancelling obsolete check %s"
+                                    proc))
+                   (kill-buffer (process-buffer proc)))))))
+      (process-send-region texinfo--flymake-proc (point-min) (point-max))
+      (process-send-eof texinfo--flymake-proc))))
+
+
 ;;; Texinfo mode
 
 ;;;###autoload
@@ -455,7 +528,10 @@ texinfo-mode
 	      (let ((prevent-filling "^@\\(def\\|multitable\\)"))
 		(if (null auto-fill-inhibit-regexp)
 		    prevent-filling
-		  (concat auto-fill-inhibit-regexp "\\|" prevent-filling)))))
+		  (concat auto-fill-inhibit-regexp "\\|" prevent-filling))))
+
+  ;; Set up Flymake support.
+  (add-hook 'flymake-diagnostic-functions #'texinfo-flymake nil t))
 
 (defvar texinfo-fillable-commands '("@noindent")
   "A list of commands that can be filled.")
-- 
2.25.1