From 2e13a01708c4681a51e0bbd16a94d2f052ce53f4 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Thu, 10 Oct 2024 21:03:45 -0700 Subject: [PATCH] Fix and improve behavior of 'eshell/clear' * lisp/eshell/esh-mode.el (eshell-clear): New function. (eshell/clear): Fix incorrect behavior, and do the right thing when 'eshell-scroll-show-maximum-output' is nil. (eshell/clear-scrollback): Call 'eshell/clear'. * test/lisp/eshell/esh-mode-tests.el (esh-mode-test/clear/eshell-command) (esh-mode-test/clear/eshell-command/erase) (esh-mode-test/clear/emacs-command) (esh-mode-test/clear/emacs-command/erase): New tests. * etc/NEWS: Mention the new 'eshell-command' (bug#73722). --- etc/NEWS | 8 ++++ lisp/eshell/esh-mode.el | 61 +++++++++++++++++++++++++----- test/lisp/eshell/esh-mode-tests.el | 42 ++++++++++++++++++++ 3 files changed, 101 insertions(+), 10 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 4346fb4aedd..b8aff8cc76f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -236,6 +236,14 @@ It removes all the buttons in the specified region. ** Eshell +--- +*** New interactive command 'eshell-clear'. +This command scrolls the screen so that only the current prompt is +visible, optionally erasing all the previous input/output as well. +Previously, the Eshell built-in command 'eshell/clear' supported this +(e.g. to call it via 'M-x'), but this new command behaves more +consistently if you have a partially-typed command at the Eshell prompt. + --- *** New user option 'eshell-command-async-buffer'. This option lets you tell 'eshell-command' how to respond if its output diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index 34ce82cfbc4..c5bcd28ef51 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -862,20 +862,61 @@ eshell-show-maximum-output (goto-char (point-max)) (recenter -1)) -(defun eshell/clear (&optional scrollback) - "Scroll contents of eshell window out of sight, leaving a blank window. -If SCROLLBACK is non-nil, clear the scrollback contents." +(defun eshell-clear (&optional clear-scrollback) + "Scroll contents of the Eshell window out of sight, leaving a blank window. +If CLEAR-SCROLLBACK is non-nil (interactively, with the prefix +argument), clear the scrollback contents. + +Otherwise, the behavior depends on `eshell-scroll-show-maximum-output'. +If non-nil, fill newlines before the current prompt so that the prompt +is the last line in the window; if nil, just scroll the window so that +the prompt is the first line in the window." + (interactive "P") + (cond + (clear-scrollback + (let ((inhibit-read-only t)) + (widen) + (delete-region (point-min) (eshell-end-of-output)))) + (eshell-scroll-show-maximum-output + (save-excursion + (goto-char (eshell-end-of-output)) + (let ((inhibit-read-only t)) + (insert-and-inherit (make-string (window-size) ?\n)))) + (when (< (point) eshell-last-output-end) + (goto-char eshell-last-output-end))) + (t + (when (< (point) eshell-last-output-end) + (goto-char eshell-last-output-end)) + (set-window-start nil (eshell-end-of-output))))) + +(defun eshell/clear (&optional clear-scrollback) + "Scroll contents of the Eshell window out of sight, leaving a blank window. +If CLEAR-SCROLLBACK is non-nil, clear the scrollback contents. + +Otherwise, the behavior depends on `eshell-scroll-show-maximum-output'. +If non-nil, fill newlines before the current prompt so that the prompt +is the last line in the window; if nil, just scroll the window so that +the prompt is the first line in the window. + +This command is for use as an Eshell command (entered at the prompt); +for clearing the Eshell buffer from elsewhere (e.g. via +\\[execute-extended-command]), use `eshell-clear'." (interactive) - (if scrollback - (eshell/clear-scrollback) + (cond + ((null eshell-current-handles) + (eshell-clear clear-scrollback)) + (clear-scrollback + (let ((inhibit-read-only t)) + (erase-buffer))) + (eshell-scroll-show-maximum-output (let ((eshell-input-filter-functions nil)) - (insert (make-string (window-size) ?\n)) - (eshell-send-input)))) + (ignore (eshell-interactive-print (make-string (window-size) ?\n))))) + (t + (recenter 0)))) (defun eshell/clear-scrollback () - "Clear the scrollback content of the eshell window." - (let ((inhibit-read-only t)) - (erase-buffer))) + "Clear the scrollback content of the Eshell window." + (eshell/clear t)) (defun eshell-get-old-input (&optional use-current-region) "Return the command input on the current line. diff --git a/test/lisp/eshell/esh-mode-tests.el b/test/lisp/eshell/esh-mode-tests.el index 306e11ce445..28839eb65cf 100644 --- a/test/lisp/eshell/esh-mode-tests.el +++ b/test/lisp/eshell/esh-mode-tests.el @@ -26,6 +26,8 @@ (require 'ert) (require 'esh-mode) (require 'eshell) +(require 'em-banner) +(require 'em-prompt) (require 'eshell-tests-helpers (expand-file-name "eshell-tests-helpers" @@ -59,4 +61,44 @@ esh-mode-test/handle-control-codes/backspace (eshell-match-command-output (format "(format \"hello%c%cp\")" ?\C-h ?\C-h) "\\`help\n"))) +(ert-deftest esh-mode-test/clear/eshell-command () + "Test that `eshell/clear' works as an Eshell command." + (let ((eshell-banner-message "") + (eshell-prompt-function (lambda () "$ "))) + (with-temp-eshell + (eshell-insert-command "echo hi") + (eshell-insert-command "clear") + (should (string-match "\\`\\$ echo hi\nhi\n\\$ clear\n+\\$ " + (buffer-string)))))) + +(ert-deftest esh-mode-test/clear/eshell-command/erase () + "Test that `eshell/clear' can erase the buffer." + (let ((eshell-banner-message "") + (eshell-prompt-function (lambda () "$ "))) + (with-temp-eshell + (eshell-insert-command "echo hi") + (eshell-insert-command "clear t") + (should (string-match "\\`\\$ " (buffer-string)))))) + +(ert-deftest esh-mode-test/clear/emacs-command () + "Test that `eshell-clear' works as an interactive Emacs command." + (let ((eshell-banner-message "") + (eshell-prompt-function (lambda () "$ "))) + (with-temp-eshell + (eshell-insert-command "echo hi") + (insert "echo b") + (eshell-clear) + (should (string-match "\\`\\$ echo hi\nhi\n\n+\\$ echo b" + (buffer-string)))))) + +(ert-deftest esh-mode-test/clear/emacs-command/erase () + "Test that `eshell-clear' can erase the buffer." + (let ((eshell-banner-message "") + (eshell-prompt-function (lambda () "$ "))) + (with-temp-eshell + (eshell-insert-command "echo hi") + (insert "echo b") + (eshell-clear t) + (should (string-match "\\`\\$ echo b" (buffer-string)))))) + ;; esh-mode-tests.el ends here -- 2.25.1