Subject: [PATCH] Add Texinfo support for Flymake

From: Okamsn <[email-masked]>
Date: Tue, 07 Dec 2021 02:48:13 +0000

Hello,

This patch adds basic Texinfo support for Flymake, following the
annotated example in the Flymake manual.  All it does is feed the
contents of the buffer to the program `makeinfo`, which either reports
errors or outputs the resulting file to the specified /dev/null.

The regexp for identifying errors and warnings is the same as used by
the package Flycheck (see here:
https://github.com/flycheck/flycheck/blob/784f184cdd9f9cb4e3dbb997c09d93e954142842/flycheck.el#L12175).
It seems to identify an optional column number, but I didn't see that in
the programs output or listed in the Man page.  The patch does not make
use of any match for that information.

The Man page says that the program will by default report 100 errors
before stopping.

While the package Flymake is required during compilation, the byte
compiler still wanted the function `flymake--log-1` declared.  This is
the function run by the macro `flymake-log`.

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