Subject: bug#51380: 29.0.50; The annotated example of a complete working Flymake backend leaves process buffers around

From: Rudolf Adamkovič <[email-masked]>
Date: Sun, 24 Oct 2021 22:01:38 +0200

I noticed that the "annotated example of a complete working Flymake backend" at

<https://www.gnu.org/software/emacs/manual/html_mono/flymake.html#Backend-functions>

leaves zombie buffers around. I traced the problem down to

┌────
│ (when (eq 'exit (process-status proc)) …
└────

The backend kills the process buffer on `'exit' but not on `'signal', which happens when Flymake kills an obsolete in-progress check. I fixed the problem locally by checking for both `(or (eq status 'exit) (eq status 'signal)'. Below, I include a macro that includes the fix.

┌────
│ (defmacro my-define-flymake-backend (name cmd regexp warning-p)
│   "Define a new Flymake backend named NAME.
│ 
│ CMD takes a buffer file name and returns a system command
│ to run to check the buffer. REGEXP matches the output of the system
│ command in three capture groups: (1) line, (2) column, and (3)
│ message. WARNING-P takes the message matched by REGEXP and decides if
│ the issue represents a warning or an error.
│ 
│ The macro defines a function called NAME representing the Flymake
│ backend and a variable called NAME that stores the current process."
│   `(defun ,name (report-fn &rest _args)
│      (defvar-local ,name nil)
│      (when (process-live-p ,name) (kill-process ,name))
│      (let ((src (current-buffer)))
│        (save-restriction
│          (widen)
│          (setq
│           ,name
│           (make-process
│            :name (symbol-name ',name)
│            :noquery t
│            :connection-type 'pipe
│            :buffer (generate-new-buffer
│                     (concat "*" (symbol-name ',name) "*"))
│            :command (with-current-buffer src
│                       (funcall ,cmd buffer-file-name))
│            :sentinel
│            (lambda (proc _event)
│              (let ((status (process-status proc)))
│                (when (or (eq status 'exit)
│                          (eq status 'signal))
│                  (unwind-protect
│                      (when (and (with-current-buffer src (eq proc ,name))
│                                 (eq status 'exit))
│                        (with-current-buffer (process-buffer proc)
│                          (goto-char (point-min))
│                          (cl-loop
│                           while (search-forward-regexp ,regexp nil t)
│                           for msg = (match-string 3)
│                           for line = (string-to-number (match-string 1))
│                           for col = (string-to-number (match-string 2))
│                           for (beg . end) = (flymake-diag-region src line col)
│                           for type = (if (funcall ,warning-p msg) :warning :error)
│                           collect (flymake-make-diagnostic src beg end type msg)
│                           into diags
│                           finally (funcall report-fn diags))))
│                    (kill-buffer (process-buffer proc))))))))
│          (process-send-region ,name (point-min) (point-max))
│          (process-send-eof ,name)))))
└────

For completeness, I call the macro above as follows:

┌────
│ (my-define-flymake-backend
│  my-flymake-vale
│  (lambda (source) (list "vale" "--output" "line" "--ext" ".md", "--no-wrap"))
│  "^stdin.md:\\([0-9]+\\):\\([0-9]+\\):\\(.*\\)$"
│  (lambda (msg) t))
└────

Rudy

In GNU Emacs 29.0.50 (build 6, x86_64-apple-darwin20.6.0, NS appkit-2022.60 Version 11.5.1 (Build 20G80))
 of 2021-10-24 built on Workstation.local
Repository revision: aea4af5119fdf130f1df7190478a23c6777f92a2
Repository branch: master
Windowing system distributor 'Apple', version 10.3.2022
System Description:  macOS 11.5.1

Configured using:
 'configure --with-json
 PKG_CONFIG_PATH=/usr/local/Cellar/zlib/1.2.11/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig'

Configured features:
ACL DBUS GIF GLIB GMP GNUTLS JPEG JSON LCMS2 LIBXML2 MODULES NOTIFY
KQUEUE NS PDUMPER PNG RSVG THREADS TIFF TOOLKIT_SCROLL_BARS WEBP XIM
ZLIB

Important settings:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Text

Minor modes in effect:
  TeX-PDF-mode: t
  shell-dirtrack-mode: t
  flymake-mode: t
  which-key-mode: t
  corfu-global-mode: t
  corfu-mode: t
  vertico-mode: t
  marginalia-mode: t
  global-diff-hl-mode: t
  yas-global-mode: t
  yas-minor-mode: t
  global-hl-todo-mode: t
  hl-todo-mode: t
  savehist-mode: t
  global-subword-mode: t
  subword-mode: t
  save-place-mode: t
  global-auto-revert-mode: t
  delete-selection-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  size-indication-mode: t
  column-number-mode: t
  line-number-mode: t
  global-visual-line-mode: t
  visual-line-mode: t
  transient-mark-mode: t

Load-path shadows:
/Users/salutis/.emacs.d/elpa/transient-20211023.2151/transient hides /Users/salutis/src/emacs/nextstep/Emacs.app/Contents/Resources/lisp/transient

Features:
(shadow sort bbdb-message fortune mail-extr emacsbug sendmail ox-md
ox-odt rng-loc rng-uri rng-parse rng-match rng-dt rng-util rng-pttrn
nxml-parse nxml-ns nxml-enc xmltok nxml-util ox-latex ox-icalendar
org-agenda org-refile ox-html table ox-ascii ox-publish ox bug-reference
helpful imenu trace edebug backtrace info-look help-fns radix-tree
elisp-refs vc-mtn vc-hg vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs
preview tex-buf font-latex latex edmacro latex-flymake tex-ispell
tex-style tex crm texmathp tex-mode shell flymake-proc flymake project
warnings org-indent image-file image-converter disp-table char-fold
cursor-sensor bbdb bbdb-site timezone modus-vivendi-theme
modus-operandi-theme modus-themes which-key corfu orderless
consult-vertico vertico marginalia consult recentf tree-widget kmacro
pdf-loader diff-hl log-view pcvs-util vc-dir ewoc vc diminish yasnippet
hl-todo finder-inf org-clock oc-csl citeproc citeproc-itemgetters
citeproc-biblatex citeproc-bibtex parsebib citeproc-cite
citeproc-subbibs citeproc-sort citeproc-name citeproc-formatters
citeproc-number rst compile citeproc-proc citeproc-disamb
citeproc-itemdata citeproc-generic-elements citeproc-macro
citeproc-choose citeproc-date citeproc-context citeproc-prange
citeproc-style citeproc-locale citeproc-term f citeproc-rt citeproc-lib
citeproc-s s let-alist queue dash savehist ls-lisp cap-words superword
subword saveplace autorevert filenotify delsel elfeed-link elfeed-show
elfeed-search elfeed-csv elfeed elfeed-curl elfeed-log xml-query
bookmark pp elfeed-db elfeed-lib vc-git diff-mode vc-dispatcher
org-element avl-tree generator ol-eww eww xdg url-queue thingatpt mm-url
ol-rmail ol-mhe ol-irc ol-info ol-gnus nnselect gnus-search eieio-opt
speedbar ezimage dframe gnus-art mm-uu mml2015 mm-view mml-smime smime
dig gnus-sum shr kinsoku svg dom gnus-group gnus-undo gnus-start
gnus-dbus dbus xml gnus-cloud nnimap nnmail mail-source utf7 netrc nnoo
parse-time gnus-spec gnus-int gnus-range message rmc puny rfc822 mml
mml-sec epa derived epg rfc6068 epg-config mm-decode mm-bodies mm-encode
mail-parse rfc2231 mailabbrev gmm-utils mailheader gnus-win gnus
nnheader gnus-util rmail rmail-loaddefs rfc2047 rfc2045 ietf-drums
text-property-search mail-utils mm-util mail-prsvr wid-edit ol-docview
doc-view jka-compr image-mode exif dired dired-loaddefs ol-bibtex
ol-bbdb ol-w3m ol-doi org-link-doi cl-extra help-mode org ob ob-tangle
ob-ref ob-lob ob-table ob-exp org-macro org-footnote org-src ob-comint
org-pcomplete pcomplete comint ansi-color ring org-list org-faces
org-entities noutline outline easy-mmode org-version ob-emacs-lisp
ob-core ob-eval org-table oc-basic bibtex iso8601 time-date ol rx
org-keys oc org-compat advice org-macs org-loaddefs format-spec
find-func cal-menu calendar cal-loaddefs tex-site info package
browse-url url url-proxy url-privacy url-expand url-methods url-history
url-cookie url-domsuf url-util mailcap url-handlers url-parse
auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs
password-cache json map url-vars seq gv subr-x byte-opt bytecomp
byte-compile cconv cl-loaddefs cl-lib iso-transl tooltip eldoc paren
electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel
term/ns-win ns-win ucs-normalize mule-util term/common-win tool-bar dnd
fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow
isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax
font-core term/tty-colors frame minibuffer cl-generic cham georgian
utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european
ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop
case-table epa-hook jka-cmpr-hook help simple abbrev obarray
cl-preloaded nadvice button loaddefs faces cus-face macroexp files
window text-properties overlay sha1 md5 base64 format env code-pages
mule custom widget hashtable-print-readable backquote threads dbusbind
kqueue cocoa ns lcms2 multi-tty make-network-process emacs)

Memory information:
((conses 16 887550 54338)
 (symbols 48 45003 4)
 (strings 32 241995 11585)
 (string-bytes 1 6618139)
 (vectors 16 86621)
 (vector-slots 8 1813636 54587)
 (floats 8 435 550)
 (intervals 56 24349 524)
 (buffers 992 23))

-- 
"I love deadlines. I love the whooshing noise they make as they go by." -- Douglas Adams, The Salmon of Doubt

Rudolf Adamkovič <[email-masked]>
Studenohorská 25
84103 Bratislava
Slovakia

[he/him]