5

So I wrote a little function for how I use eat.

In eat, you can have multiple terminal buffers open, and they are differentiated by incrementing numbers. The official way to open an additional buffer is to run eat with a prefix argument like C-u M-x eat. I wrote my little function to do this for me, because I don't use prefix arguments/C-u anywhere else and just couldn't remember it.

So this function checks the buffer list for existing eat buffers. If there is one with a number at the end, it takes this number, increments it by one and then opens a new eat buffer with this incremented number. If there is just one without a number, it opens a new buffer with the number one, since the first buffer is created without a number per default. If there is no eat buffer at all, it just calls eat to create one. This is the function:

(defun eat-more ()
  "Open a new terminal"
  (interactive)
  (if (match-buffers "\*eat\*")
      (if (string-match ".*<.>" (prin1-to-string (last (match-buffers "\*eat\*"))))
	  (eat (funcall eat-default-shell-function) (+ (string-to-number (substring (prin1-to-string (last (sort (match-buffers "\*eat\*")))) -4 -3)) 1))
	(eat (funcall eat-default-shell-function) 1))
    (eat)))

This works as intended, but the line getting and incrementing the buffer number looks really awkward. So my question is: How could I improve that to make it more readable without changing the logic completely?

There are probably shorter ways to do this by just calling eat with a prefix argument in the function itself, or something like that. But I am interested in interacting with the buffer list and all this nested string slicing and converting feels off. The actual eat function is defined here in eat.el Do you have any suggestions?

you are viewing a single comment's thread
view the rest of the comments
[-] midribbon_action 2 points 4 days ago

As other comments have pointed out, and you already mentioned this as a possibility, this is how I would write it:

(defun eat-more ()
  "Open a new terminal."
  (interactive)
  (eat nil t))

However, given your goal of understanding commands and the buffer list better, I'll try to explain a little better.

The first parameter, the shell, when left nil, will use your default eat-shell, so the funcall in your current implementation is redundant. The eat-shell can be customized separately if necessary.

The <3> or <5> or whatever suffix in the eat buffer name is actually not generated by eat itself, eat is using generate-new-buffer, which is an Emacs built-in function that relies on the C function generate-new-buffer-name.

So what you are attempting to do is not just re-implement a feature eat already has, but a core function within Emacs itself. If you don't rely on built-in functionality, I would argue that you are not familiarizing yourself with elisp development, you are really creating your own language.

However, re-implementing what eat does can maybe be a good exercise, so to use the built-in function to help us, I would probably write it like something like this:

(defun eat-more ()
  "Open a new terminal."
  (interactive)
  (require 'eat)
  (eat
   nil
   (let ((name (generate-new-buffer-name eat-buffer-name)))
     (when (string-match "<\\([[:digit:]]+\\)>" name)
       (string-to-number (match-string 1 name))))))

One thing I'd like to draw attention to is the use of the variable eat-buffer-name, which is defined by eat and is customizable, so even though most people are using the default name "*eat*", this could be different for some users. However, using this variable means we need to 'require' the eat package first. In the simpler answer, we were relying on the fact that the (eat ...) command is autoloaded, and can be called without requiring the package first. But that isn't true for the eat-buffer-name variable.

this post was submitted on 27 Aug 2025
5 points (100.0% liked)

Emacs

2638 readers
1 users here now

Our infinitely powerful editor.

founded 5 years ago
MODERATORS