Killing buffers whose names start with a particular string

风格不统一 提交于 2019-11-30 13:48:25

问题


Here's my problem: I use Emacs and get lots of buffers that are pretty useless all the time, like *Messages* or *Completions*.

I want to bind \C-y to close all buffers that start with * except for *shell* (and *shell* < k >) buffers.

To do that, I'd like to add some Emacs-Lisp in my .emacs file:

(defun string-prefix s1 s2
  (if (> (string-length s1) (string-length s2)) nil
    (string=? s1 (substring s2 0 (string-length s1))) ))

(defun curry2
  (lambda (f)
    (lambda (x)
      (lambda (y)
    (f x y) ))))

(defun filter
  (lambda (f l)
    (if (null? l) '()
      (let ((rest (cdr l)))
    (if (f (car l)) (cons (car l) rest)
      rest) ))))


(defun kill-useless (arg)
  (interactive "p")
  (map 'kill-buffer
       (filter
    (not ((curry2 string-prefix) "*shell*"))
    (list-buffers)
    ) ))

(global-set-key "\C-y" 'kill-useless)

I've already tested string-prefix and curry2 using Scheme and filter seems pretty straightforward. Sadly I just can't get kill-useless to work properly.

It says filter: Invalid function: (curry2 string-prefix).

Now, the thing is I kind of suck at Emacs-Lisp, I don't really use any Lisp except Scheme, and in Scheme (MIT), this works:

(filter ((curry2 string-prefix?) "*shell") '("*shell*" "*sh22" "eel"))
;Value 5: ("*shell*")

I'd like:

  1. a way to fix my code
  2. suggestions on how to do this in a different way

Thanks!


回答1:


An alternate approach:

(require 'cl)

(defun is-useless-buffer (buffer)
  (let ((name (buffer-name buffer)))
    (and (= ?* (aref name 0))
         (not (string-match "^\\*shell\\*" name)))))

(defun kill-useless-buffers ()
  (interactive)
  (loop for buffer being the buffers
        do (and (is-useless-buffer buffer) (kill-buffer buffer))))



回答2:


C-h f kill-matching-buffers RET

kill-matching-buffers is an interactive compiled Lisp function in `files.el'.

(kill-matching-buffers REGEXP &optional INTERNAL-TOO)

Kill buffers whose name matches the specified REGEXP. The optional second argument indicates whether to kill internal buffers too.




回答3:


Keep in mind elisp isn't scheme, or even common lisp. The syntax and semantics are different. For example, defun requires a parameters list surrounded by parentheses. Also, currying isn't really possible in elisp.

Fortunately, elisp has builtins for most of what you want to do. For string-prefix you can use the string-prefix-p builtin. For filter, you can use remove-if-not, or remove-if for the inverse.

For the currying you can use the apply-partially builtin function. To get a function that matches strings with the prefix "*shell*", try something like this:

(apply-partially 'string-prefix-p "*shell*")

You can use it like this:

(mapcar
 (apply-partially 'string-prefix-p "*shell*")
 '("*shell*" "foo" "*shell*<2>"))

; results in
(t nil t)

(require 'cl) ; for remove-if
(remove-if
 (apply-partially 'string-prefix-p "*shell*")
 '("*shell*" "foo" "*shell*<2>"))

; results in
("foo")



回答4:


It can be a good idea to see what you will delete before deleting it, to play safe.

In Icicles, by default C-x k is a multi-command that you can use to kill any number of buffers that match your minibuffer input. In this case, you would type * TAB to see all buffer names starting with * as completion candidates.

You can then narrow the matches, in several ways. When all of the matches remaining are what you want, hit C-! to delete all of those buffers.

In the case you presented, you do not want to delete buffers named *shell.... So after * TAB you would hit S-SPC and then enter another pattern to match: shell, then S-TAB. That narrows to only the *shell... buffers that you do not want to kill. You then hit C-~ to subtract those matches (complement). That leaves all of the buffers except the shell buffers. Hit C-! and they're all killed.

You can also kill individual buffers by just control-clicking their names in *Completions*: C-mouse-2.

More generally, in Icicles every multi-command that reads a buffer name lets you use S-delete (Shift + the Delete key) to kill buffer candidates.

http://www.emacswiki.org/emacs/Icicles_-_Multi-Commands

http://www.emacswiki.org/emacs/Icicles_-_More_About_Multi-Commands




回答5:


I found kill-matching-functions prompted me for unmodified buffers, which isn't what I wanted. The function below will kill buffers matching a prefix (as in the title of the question). Not exactly what you wanted, but maybe people like me who come here from Google will find this useful.

(require 'cl)
(defun kill-buffers-with-prefix (prefix)
  "Kill buffers whose names start with the given prefix"
  (interactive "sPrefix to kill: ")
  (loop for buffer in (buffer-list)
        do (if (string-prefix-p prefix (buffer-name buffer))
               (kill-buffer buffer))))



回答6:


To kill all other buffers

(defun px-kill-other-buffers ()
  "Kill all other buffers."
  (interactive)
  (mapc 'kill-buffer (delq (current-buffer) (buffer-list))))

To search the beginning of a string

(defun string-starts-with-p (string prefix)
    "Return t if STRING starts with prefix."
    (and
     (string-match (rx-to-string `(: bos ,prefix) t) string)
     t))


来源:https://stackoverflow.com/questions/5097561/killing-buffers-whose-names-start-with-a-particular-string

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!