Kill This Buffer

[Editorial Note: Sorry about the lousy formatting. Org2blog is misbehaving again so I had to paste the HTML into the WordPress editor.]

Ben Maughan over at Pragmatic Emacs has a really nice tip. It's one of
those things that you (or at least I) don't think about but once you
see the tip, you think, “That's just what I need.” The idea is to kill
the current buffer without asking
.

Maughan asks how many times you've called kill-buffer via
Ctrl+x k】and wanted to kill some buffer other than the one you're in. I can't
ever remember doing that. Maughan provides a one line fix to your
init.el that will just delete the current buffer without asking.
Perfect.

If you think you'll sometimes want the old behavior and don't want to
remember kill-buffer, it's trivial to add a bit of Elisp that
calls kill-this-buffer unless the universal argument is provided in
which case it calls kill-buffer. Bind this to
Ctrl+x k】 and you have the best of both worlds.
Here's some code that does that

(defun jcs-kill-a-buffer (askp)
  (interactive "P")
  (if askp
      (kill-buffer (funcall completing-read-function
                            "Kill buffer: "
                            (mapcar #'buffer-name (buffer-list))))
    (kill-this-buffer)))

(global-set-key (kbd "C-x k") 'jcs-kill-a-buffer)
This entry was posted in General and tagged . Bookmark the permalink.
  • brilliant tip! thanks for sharing

  • verdammelt

    I think you can change the whole call to kill-buffer with `(call-interactively #'kill-buffer)`. `kill-buffer` will then prompt for the buffer name like normal.

    (I've only tried it out in the repl - not sure if it really *works*)

    • jcs

      Yes, good idea. What I did was pretty simple but I was surprised that there wasn't an easier way. I didn't think of call-interactively.

      • Fuco

        Also, `funcall completing-read-function` is equivalent to just using `completing-read` :)

        • jcs

          Hmmm. Interesting. Right you are, of course. It turns out that completing-read does (essentially) a funcall on completing-read-function. The default value of completing-read-function is completing-read-default, which is the function that does the work if you haven't overridden it with something like swiper.

  • Fuco

    Personally, I use `M-k` binding for this... killing sentences is, I suppose, even rarer than killing other buffers ;D

    • Omar

      Maybe you're just a better writer than other people? I kill sentences all the time.

      • Fuco

        I wouldn't say better, I probably just have different workflow :)

  • titaniumbones

    Huh, this code was working for me until I think today, when I started getting this failure:

    ```
    Debugger entered: nil
    edebug--display-1(t 14 after)
    edebug--display(t 14 after)
    edebug-debugger(14 after t)
    edebug-after(13 14 t)
    (if (edebug-after 0 1 askp) (edebug-after (edebug-before 2) 12 (kill-buffer (edebug-after (edebug-before 3) 11 (funcall (edebug-after 0 4 completing-read-function) "Kill buffer: " (edebug-after (edebug-before 5) 10 (mapcar (edebug-after ... 7 ...) (edebug-after ... 9 ...))))))) (edebug-after (edebug-before 13) 14 (kill-this-buffer)))
    (edebug-after (edebug-before 0) 15 (if (edebug-after 0 1 askp) (edebug-after (edebug-before 2) 12 (kill-buffer (edebug-after (edebug-before 3) 11 (funcall (edebug-after 0 4 completing-read-function) "Kill buffer: " (edebug-after (edebug-before 5) 10 (mapcar ... ...)))))) (edebug-after (edebug-before 13) 14 (kill-this-buffer))))
    (lambda nil (edebug-after (edebug-before 0) 15 (if (edebug-after 0 1 askp) (edebug-after (edebug-before 2) 12 (kill-buffer (edebug-after (edebug-before 3) 11 (funcall (edebug-after 0 4 completing-read-function) "Kill buffer: " (edebug-after ... 10 ...))))) (edebug-after (edebug-before 13) 14 (kill-this-buffer)))))()
    edebug-enter(jcs-kill-a-buffer (nil) (lambda nil (edebug-after (edebug-before 0) 15 (if (edebug-after 0 1 askp) (edebug-after (edebug-before 2) 12 (kill-buffer (edebug-after (edebug-before 3) 11 (funcall (edebug-after 0 4 completing-read-function) "Kill buffer: " (edebug-after ... 10 ...))))) (edebug-after (edebug-before 13) 14 (kill-this-buffer))))))
    edebug-enter(jcs-kill-a-buffer (nil) (lambda nil (edebug-after (edebug-before 0) 15 (if (edebug-after 0 1 askp) (edebug-after (edebug-before 2) 12 (kill-buffer (edebug-after (edebug-before 3) 11 (funcall (edebug-after 0 4 completing-read-function) "Kill buffer: " (edebug-after ... 10 ...))))) (edebug-after (edebug-before 13) 14 (kill-this-buffer))))))
    jcs-kill-a-buffer(nil)
    funcall-interactively(jcs-kill-a-buffer nil)
    call-interactively(jcs-kill-a-buffer nil nil)
    command-execute(jcs-kill-a-buffer)
    ```

    I can't decipher this at all, any idea what's going on?

    • jcs

      I don't know; it looks odd. You can see from the backtrace that jcs-kill-a-buffer was called without an argument and subsequently called kill-this-buffer as expected. Then there are calls to completing-read-function as if it were trying to ask for the buffer to kill. I don't have time right now to dig into the kill-this-buffer to see if this is correct behavior--all I can tell you is that it's still working correctly for me. I'm on stock 25.1 for OS X with all my packages upgraded.

      • titaniumbones

        Yeah, I don't know exactly what's going on -- it seems strange, right? switching to (call-interactively #'kill-buffer) as suggested in an earlier comment seems to have helped, but I haven't been able to do proper debugging, so I'm not sure what the real cause was