12

After looking at this answer I find it hard to believe there is no way to clear the eShell.

Does anybody know of a short function or method to delete the entire buffer. Pressing C-l just scrolls the text, as soon as enter is pressed all of that text comes back.

Thanks

Startec
  • 1,354
  • 1
  • 13
  • 30

7 Answers7

19

Running clear with 1, as in clear 1 works.

enter image description here


How could you have found this out? We know we want to look for a function about eshell and it has to do with clear. So, why not do C-h f and type eshell clear. This produces two functions:

  1. eshell/clear-scrollback
  2. eshell/clear

If we select eshell-scrollback, Emacs shows us usage:

eshell/clear-scrollback is a compiled Lisp function in ‘esh-mode.el’.

(eshell/clear-scrollback)

Clear the scrollback content of the eshell window.

We try running eshell/clear-scrollback and it clears the screen. Ok, we can look at it's implementation but before that let's look at the other function eshell/clear. When we select that after C-h f and eshell clear, we get:

eshell/clear is an interactive compiled Lisp function in
‘esh-mode.el’.

(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.

This tells us that we could run clear 1 to clear the screen. But, why are there two functions? If we look at the implementation of eshell/clear, we can see that the other function is actually used in it. To find the implementation simply click on the esh-mode.el in the usage buffer of eshell/clear.

(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."
  (interactive)
  (if scrollback
      (eshell/clear-scrollback)
    (insert (make-string (window-size) ?\n))
    (eshell-send-input)))

You can see that at the end this function sends any input which was present at the time of clearing the screen. To get around it, I wrote this little function:

(defun run-this-in-eshell (cmd)
  "Runs the command 'cmd' in eshell."
  (with-current-buffer "*eshell*"
    (end-of-buffer)
    (eshell-kill-input)
    (message (concat "Running in Eshell: " cmd))
    (insert cmd)
    (eshell-send-input)
    (end-of-buffer)
    (eshell-bol)
    (yank)))

The benefits of this function are that if you put it in a lambda function and bind it to a key like this:

(bind-keys*
    ("C-<backspace>" . (lambda () ; clear shell
                     (interactive)
                     (run-this-in-eshell "clear 1"))))

It will first kill the current input, run clear 1 and then yank the input back. This way you can also clear eshell from any other buffer using the keybinding.

Some other functions provided will wipe out any buffer they are ran in. So if you used the keybinding to clear eshell from some other buffer, it will instead clear THAT buffer.

scribe
  • 930
  • 4
  • 15
  • 3
    This is so good! Solid answer, then a thorough walk through of how to do this type of digging and reasoning yourself. Thank you for the education! – young_souvlaki Aug 19 '20 at 16:55
  • Is there a simple way to add an `eshell-mode-hook` local binding without the need for your function? Tobias' answer didn't work for me. I can't figure out how to pass `eshell/clear` the non-nil argument. When I try to use `eshell/clear-scrollback` as the command, I get a "wrong type argument commandp" error. `(add-hook 'eshell-mode-hook (lambda () (local-set-key (kbd "C-l") 'eshell/clear-scrollback)))` – young_souvlaki Aug 19 '20 at 17:42
  • I am a little confused as to what you're trying to do here. Do you just want to bind a lambda to a key that sends eshell a "clear 1" command? Your usage of a hook to add a key binding looks funny, I am not sure if people use hooks that way, but I am no expert. I use the use-package library for all things I can. – scribe Aug 20 '20 at 00:19
  • I got the syntax [here](https://www.gnu.org/software/emacs/manual/html_node/efaq/Binding-keys-to-commands.html). I'm not sure I want to "send input", rather I'd like to call the eshell command `clear` with the argument `1` or call `eshell/clear-scrollback`. The difference as I understand it: Sending input would mean entering the command as if it were typed in the shell. Calling the command would be equivalent to `M-x clear 1` or `M-x clear-scrollback`. – young_souvlaki Aug 20 '20 at 18:45
  • 1
    I might be wrong now but I think you are confusing the fact that eshell is emacs' shell! So sending it input is the same as calling a function like `M-x `, e. g., `M-x magit` does the same thing as `obla/di/da $ magit` in eshell. You can even do `obla/di/da $ (message "Peace")` and it will display "Peace" in the mini-buffer. – scribe Aug 20 '20 at 23:32
  • 1
    You might try something like this: `(add-hook 'eshell-mode-hook (lambda () (local-set-key (kbd "C-l") (eshell/clear 1))))` – scribe Aug 20 '20 at 23:35
  • Exemplary answer, I wish I could upvote more. – gsl Sep 26 '21 at 14:04
  • What was wrong with the `eshell/clear` function that needed writing your own? – user129393192 Apr 26 '23 at 06:21
11

There is a function in the current development version, as you can see on the emacs-devel mailing list.

The function is very simple:

(defun eshell/clear ()
  "Clear the eshell buffer."
  (let ((inhibit-read-only t))
    (erase-buffer)
    (eshell-send-input)))

Typing clear in eshell will then result in clearing the buffer.

Tianxiang Xiong
  • 3,848
  • 16
  • 27
  • oh wow. how will i know when this is available in a main release? – Startec May 19 '15 at 08:57
  • 1
    You don't need to wait for the next release. You can just add this definition to your `~/.emacs.d/init.el` file. You will know that it's available by checking for its definition with `C-h f eshell/clear RET`. –  May 19 '15 at 10:21
  • I am using an older version of Emacs which did not require `(eshell-send-input)` -- that line of code created an extra command prompt. – lawlist Sep 28 '17 at 17:47
5

This does it to one, insted of two lines.

;Clear the eshell buffer.
(defun eshell/clear ()      
   (let ((eshell-buffer-maximum-lines 0)) (eshell-truncate-buffer)))

Typing clear in eshell will then result in clearing the buffer.

K.D.G
  • 51
  • 1
  • 3
  • 2
    Whoever left a demerit (downvote) without leaving a helpful constructive comment, please don't do that again -- especially when you see a newcomber to this forum! I am an intermediate Emacs user and I shouldn't have to sit here scratching my head to try and figure out why this answer received a downvote! It should not be necessary for me to try out the answer to *maybe* figure out why it was downvoted! – lawlist Sep 29 '17 at 05:23
  • 1
    If you add `(interactive)` after the defun declaration, all works as expected. – Paradiesstaub Jan 03 '18 at 03:02
  • 2
    Slightly better then default, clear, which doesn't seem to really clear. – Didier A. Aug 23 '18 at 05:14
3

While there is a built-in eshell/clear in recent versions of Emacs, it does something rather unfortunate: when there is unsent input at the current prompt, clearing the buffer sends the input. This can be problematic if the user has entered partial input.

The following version will clear the buffer while preserving unsent input. This is more comint-like.

(defun my/eshell/clear ()
  "Clear `eshell' buffer.

Similar to the behavior of `comint-clear-buffer' in `shell'."
  (interactive)
  (let ((input (eshell-get-old-input)))
    (eshell/clear-scrollback)
    (eshell-emit-prompt)
    (insert input)))

You can then bind C-c M-o to that function by adding the following to you configuration. Recall that C-c M-o is bound to comint-clear-buffer in shell-mode-map so it will be easier for you to remember it.

(add-hook 'eshell-mode-hook
 (lambda ()
   (define-key eshell-mode-map "\C-c\ \M-o" 'my/eshell/clear)))
Muihlinn
  • 2,576
  • 1
  • 14
  • 22
Tianxiang Xiong
  • 3,848
  • 16
  • 27
3

I use make eshell buffers and I rename them accordingly. So a slight modification to @scribe's answer works perfectly on eshell buffers with anyname.

(defun run-this-in-eshell (cmd)
    "Runs the command 'cmd' in eshell."
    (end-of-buffer)
    (eshell-kill-input)
    (message (concat "Running in Eshell: " cmd))
    (insert cmd)
    (eshell-send-input)
    (end-of-buffer)
    (eshell-bol)
    (yank))

(add-hook 'eshell-mode-hook (lambda () 
    (interactive) 
    (local-set-key (kbd "C-l") 
    (run-this-in-eshell "clear 1"))))
Muihlinn
  • 2,576
  • 1
  • 14
  • 22
1

The doc string of eshell/clear says:

(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.

So call clear t on the Eshell prompt to clear all Eshell buffer contents.

For binding of the command to a key you can use something like the following in eshell-mode-hook:

(local-set-key (kbd "C-<backspace>") (lambda () (interactive) (eshell/clear 1)))

This answer is similar to scribe's answer and I initially wanted just to comment that one. But, then I thought that this answer goes a bit further. It also gives you a hint on how to use Eshell commands and how to discover their comments yourself.

Tobias
  • 32,569
  • 1
  • 34
  • 75
0

A version of @scribe's code with no helper functions, no debug messages, improved compatibility with per-project Eshell buffers in Emacs 29+, lazy initialization on load, a more standard keyboard shortcut, and fixed clearing with no input:

(with-eval-after-load 'esh-mode
  (keymap-set eshell-mode-map "C-l"
              (lambda ()
                (interactive)
                (let ((has-input (> (point) eshell-last-output-end)))
                  (when has-input
                    (end-of-buffer)
                    (eshell-kill-input))
                  (insert "clear 1")
                  (eshell-send-input)
                  (when has-input
                    (end-of-buffer)
                    (eshell-bol)
                    (yank))))))