From d418c7a9a88cc2c5aff2e0ff7ad9681c0c0016bb Mon Sep 17 00:00:00 2001 From: Davide Masserut Date: Wed, 30 Aug 2023 16:38:07 +0200 Subject: [PATCH] Display the exit code if the last command failed in Eshell * etc/NEWS: Announce change. * lisp/eshell/esh-cmd.el (eshell-exec-lisp): (eshell-lisp-command): Use new helper function. * lisp/eshell/esh-io.el: (eshell-close-handles): Use new helper function. (eshell-update-last-command-status): Add new helper function. * test/lisp/eshell/em-io-tests.el (em-io-test/modeline-after-failure): Add new test. --- etc/NEWS | 3 +++ lisp/eshell/esh-cmd.el | 8 ++++---- lisp/eshell/esh-io.el | 17 +++++++++++++++-- test/lisp/eshell/esh-io-tests.el | 15 +++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 9a98db8c83a..810172e3b11 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -370,6 +370,9 @@ to load the edited aliases. Running 'rgrep' in Eshell now uses the Emacs grep facility instead of calling external rgrep. +--- +*** If the last command failed, its exit code is now displayed in the modeline. + ** Pcomplete --- diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 80066263396..3672481a66a 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -1407,10 +1407,10 @@ eshell-exec-lisp ;; command status to some non-zero value to indicate an error; to ;; match GNU/Linux, we use 141, which the numeric value of ;; SIGPIPE on GNU/Linux (13) with the high bit (2^7) set. - (setq eshell-last-command-status 141) + (eshell-update-last-command-status 141) nil) (error - (setq eshell-last-command-status 1) + (eshell-update-last-command-status 1) (let ((msg (error-message-string err))) (if (and (not form-p) (string-match "^Wrong number of arguments" msg) @@ -1481,8 +1481,8 @@ eshell-lisp-command (unless eshell-allow-commands (signal 'eshell-commands-forbidden '(lisp))) (catch 'eshell-external ; deferred to an external command - (setq eshell-last-command-status 0 - eshell-last-arguments args) + (eshell-update-last-command-status 0) + (setq eshell-last-arguments args) (let* ((eshell-ensure-newline-p (eshell-interactive-output-p)) (command-form-p (functionp object)) (result diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el index c07f871dd37..96ce08051b4 100644 --- a/lisp/eshell/esh-io.el +++ b/lisp/eshell/esh-io.el @@ -70,6 +70,7 @@ (require 'esh-arg) (require 'esh-util) +(require 'compile) (eval-when-compile (require 'cl-lib)) @@ -170,7 +171,7 @@ eshell-redirection-operators-alist (defvar eshell-current-handles nil) -(defvar eshell-last-command-status 0 +(defvar-local eshell-last-command-status 0 "The exit code from the last command. 0 if successful.") (defvar eshell-last-command-result nil @@ -362,7 +363,7 @@ eshell-close-handles RESULT is the quoted value of the last command. If nil, then use the value already set in `eshell-last-command-result'." (when exit-code - (setq eshell-last-command-status exit-code)) + (eshell-update-last-command-status exit-code)) (when result (cl-assert (eq (car result) 'quote)) (setq eshell-last-command-result (cadr result))) @@ -670,5 +671,17 @@ eshell-output-object (dolist (target targets) (eshell-output-object-to-target object target)))) +(defun eshell-update-last-command-status (exit-code) + "Set `eshell-last-command-status' to EXIT-CODE and update `mode-line-process'." + (setq mode-line-process + (when (> exit-code 0) + (list + (let ((out-string (format ":[%s]" exit-code)) + (msg (format "Last command exited with code %s" exit-code))) + (propertize out-string + 'help-echo msg + 'face 'compilation-mode-line-fail)))) + eshell-last-command-status exit-code)) + (provide 'esh-io) ;;; esh-io.el ends here diff --git a/test/lisp/eshell/esh-io-tests.el b/test/lisp/eshell/esh-io-tests.el index ce80f3a8f08..c134f262007 100644 --- a/test/lisp/eshell/esh-io-tests.el +++ b/test/lisp/eshell/esh-io-tests.el @@ -23,6 +23,7 @@ (require 'ert-x) (require 'esh-mode) (require 'eshell) +(require 'compile) (require 'eshell-tests-helpers (expand-file-name "eshell-tests-helpers" @@ -370,4 +371,18 @@ esh-io-test/virtual/dev-kill (eshell-insert-command "echo three >> /dev/kill") (should (equal (car kill-ring) "twothree")))) +(ert-deftest esh-io-test/modeline-after-failure () + "Check that exit code is displayed after a failure." + (with-temp-eshell + (let ((debug-on-error nil)) + (eshell-insert-command "(zerop \"foo\")")) ; A failed command. + (should (equal-including-properties + mode-line-process + (list + (let ((out-string (format ":[%s]" eshell-last-command-status)) + (msg (format "Last command exited with code %s" eshell-last-command-status))) + (propertize out-string + 'help-echo msg + 'face 'compilation-mode-line-fail))))))) + ;;; esh-io-tests.el ends here -- 2.42.0