summaryrefslogtreecommitdiffstats
path: root/articles/c-d_to_close_eshell.org
blob: 0be307a169db9c19ebc133f40e1f66686a8e5a68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#+TITLE:
#+OPTIONS: toc:nil
#+HTML_LINK_UP: ../blog.html

* C-d to close eshell                      :eshell:emacs:elisp:config:

One of the "tricks" that I have learned to use when working with
terminals is using ~C-d~ to close them, or when working on a TTY
logout. It somehow grew to the extent that if I can't use it, I get
annoyed, like with ~eshell~.

I have customized ~ansi-term~ to immediately close its buffer after the
shell quits. This makes it very easy to start an ~ansi-term~, which I've
bound to ~C-c t~, run a quick command (perhaps ~make~, or similar), ~C-d~,
and I'm out. I want that for my ~eshell~ too.

There are a few conditions that I want met before the buffer is
killed, though.

1. Since ~eshell~ is an Emacs mode like any other, ~C-d~ is usually used
   to forward-kill characters, I don't want to lose this.
2. I only want it to quit when the line of input is empty.

The following piece of code make sure these conditions are met.

1. It interactively calls =delete-char=, which keeps keybindings like
   ~C-4 C-d~ to delete 4 characters working.
2. It catches the error condition which is signaled whenever
   =delete-char= can't do it's job (like when there's nothing left to
   delete in the buffer).
3. It checks to make sure that the signaled error is the =end-of-buffer=
   error. I don't want to kill the buffer if I try to delete more
   characters than are in the buffer because I feel that could cause
   irritating surprises.
4. It checks of the cursor is at the ~eshell~ prompt. This, combined
   with only responding to the =end-of-buffer= error, makes sure we're
   on an empty line and not just at the end of the input. Sometimes
   keys are pressed at the wrong time and I don't want to have to
   re-type a command just because I was being an idiot.
5. If the right conditions aren't met, signal the error again so I can
   see what's going on.

#+BEGIN_SRC emacs-lisp
  (defun eshell-C-d ()
    "Either call `delete-char' interactively or quit."
    (interactive)
    (condition-case err
        (call-interactively #'delete-char)
      (error (if (and (eq (car err) 'end-of-buffer)
                      (looking-back eshell-prompt-regexp))
                 (kill-buffer)
               (signal (car err) (cdr err))))))
#+END_SRC

I then bind this to =C-d= in eshell.

#+BEGIN_SRC emacs-lisp
  (add-hook 'eshell-mode-hook
            (lambda () (local-set-key (kbd "C-d") #'eshell-C-d)))
#+END_SRC