Use a process sentinel when you want to react to a process exiting. e.g.:
Refer to C-hig (elisp)Sentinels
In this case shell
only calls shell-mode
when (and after) starting the inferior process, so we can use shell-mode-hook
to add the sentinel.
As @Tobias points out in the comments, set-process-sentinel
will clobber any existing sentinel for that process. shell
will always have a sentinel (exactly what it is can vary), and we can call it first.
(defun my-shell-mode-hook ()
"Custom `shell-mode' behaviours."
;; Kill the buffer when the shell process exits.
(let* ((proc (get-buffer-process (current-buffer)))
(sentinel (process-sentinel proc)))
(set-process-sentinel
proc
`(lambda (process signal)
;; Call the original process sentinel first.
(funcall #',sentinel process signal)
;; Kill the buffer on an exit signal.
(and (memq (process-status process) '(exit signal))
(buffer-live-p (process-buffer process))
(kill-buffer (process-buffer process)))))))
(add-hook 'shell-mode-hook 'my-shell-mode-hook)
Alternatively, @Tobias has provided an alternative using advice-add
:
(defun add-process-sentinel (sentinel &optional process)
"Add SENTINEL to PROCESS.
PROCESS defaults to the process of the current buffer.
Use this function with care.
If there is already a process sentinel SENTINEL is used as after-advice.
That can fail if the process sentinel is reset by some other function."
(unless process
(setq process (get-buffer-process (current-buffer))))
(let ((old (process-sentinel process)))
(cond
((symbolp old)
(advice-add old :after sentinel))
((null old)
(set-process-sentinel process sentinel))
(t (warn "Cannot set sentinel %S for process %S." sentinel process)))))
(defun my-shell-mode-hook ()
"Custom `shell-mode' behaviours."
;; Kill the buffer when the shell process exits.
(add-process-sentinel
(lambda (process signal)
(and (memq (process-status process) '(exit signal))
(buffer-live-p (process-buffer process))
(kill-buffer (process-buffer process))))))
(add-hook 'shell-mode-hook 'my-shell-mode-hook)