-- Leo's gemini proxy

-- Connecting to gem.librehacker.com:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Emacs: Gnome Notification After Async Command (publ. 2024-03-04)


The last few weeks I've been moving more of my work out of Gnome Console into Emacs. A lot of that Console work was just calling one-off shell commands, so I figured why not call those commands using shell-command or async-shell-command from Emacs. I take the the commonly used, longer-running commands and wrap them in async-shell-command inside of a simple interactive function with an easy to remember name.


The thing I was missing after the switch, however, is that after command completion, Gnome Console would send a notification to Gnome shell, which would pop up below the notification area and do a good job of getting my attention. This was helpful after running a command that takes an twenty minutes to complete, so I want some kind of notification when it is done. Emacs, however, just sends a message to the echo area, which is easily missed and often quickly removed by some other command.


Fortunately, Gnome Shell includes a command-line utility called "notify-send" which simply requires a string passed-in as an argument. Example usage would be "guix system reconfigure mysystem.scm && notify-send done". That basically works, but it is a bother to add that onto each call to async-shell-command, and also it doesn't pass the command name or termination signal on to the notification.


Unfortunately, Emacs doesn't currently (29.1) have a hook available to do anything after the async process terminates. I e-mailed emacs-devel suggesting such a hook. In the meantime, it is possible to get what I want by overriding the sentinel function from simple.el. Here is the original function:


(defun shell-command-sentinel (process signal)
  (when (memq (process-status process) '(exit signal))
    (shell-command-set-point-after-cmd (process-buffer process))
    (message "%s: %s."
             (car (cdr (cdr (process-command process))))
             (substring signal 0 -1))))

And here is the override function in my init.el:


(defun shell-command-sentinel (process signal)
  (when (memq (process-status process) '(exit signal))
    (shell-command-set-point-after-cmd (process-buffer process))
    (let ((command-string (car (cdr (cdr (process-command process)))))
          (signal-string (substring signal 0 -1)))
      (message "%s: %s." command-string signal-string)
      (start-process "notify" nil "notify-send"
                     (concat command-string ": " signal-string)))))

I still think it would be good to have a real hook there, with the sentinel passing the process and signal to the callback(s). But this override is sufficient for my present needs.


Copyright


This work © 2024 by Christopher Howard is licensed under Attribution-ShareAlike 4.0 International.


CC BY-SA 4.0 Deed

-- Response ended

-- Page fetched on Tue May 21 11:47:33 2024