in Helm I ignore some buffers from showing when using C-x b
, I'm looking for a way to make the commands previous-buffer
and next-buffer
behave the same ignoring some buffers.
3 Answers
(defcustom my-skippable-buffers '("*Messages*" "*scratch*" "*Help*")
"Buffer names ignored by `my-next-buffer' and `my-previous-buffer'."
:type '(repeat string))
(defun my-change-buffer (change-buffer)
"Call CHANGE-BUFFER until current buffer is not in `my-skippable-buffers'."
(let ((initial (current-buffer)))
(funcall change-buffer)
(let ((first-change (current-buffer)))
(catch 'loop
(while (member (buffer-name) my-skippable-buffers)
(funcall change-buffer)
(when (eq (current-buffer) first-change)
(switch-to-buffer initial)
(throw 'loop t)))))))
(defun my-next-buffer ()
"Variant of `next-buffer' that skips `my-skippable-buffers'."
(interactive)
(my-change-buffer 'next-buffer))
(defun my-previous-buffer ()
"Variant of `previous-buffer' that skips `my-skippable-buffers'."
(interactive)
(my-change-buffer 'previous-buffer))
(global-set-key [remap next-buffer] 'my-next-buffer)
(global-set-key [remap previous-buffer] 'my-previous-buffer)
Or if you wanted to ignore buffer names matching a pattern, you could use this variant.
(defcustom my-skippable-buffer-regexp
(rx bos (or "*Messages*" "*scratch*" "*Help*") eos)
"Matching buffer names are ignored by `my-next-buffer'
and `my-previous-buffer'."
:type 'regexp)
(defun my-change-buffer (change-buffer)
"Call CHANGE-BUFFER until `my-skippable-buffer-regexp' doesn't match."
(let ((initial (current-buffer)))
(funcall change-buffer)
(let ((first-change (current-buffer)))
(catch 'loop
(while (string-match-p my-skippable-buffer-regexp (buffer-name))
(funcall change-buffer)
(when (eq (current-buffer) first-change)
(switch-to-buffer initial)
(throw 'loop t)))))))
(defun my-next-buffer ()
"Variant of next-buffer' that skips
my-skippable-buffer-regexp'."
(interactive)
(my-change-buffer 'next-buffer))
(defun my-previous-buffer ()
"Variant of previous-buffer' that skips
my-skippable-buffer-regexp'."
(interactive)
(my-change-buffer 'previous-buffer))
(global-set-key [remap next-buffer] 'my-next-buffer)
(global-set-key [remap previous-buffer] 'my-previous-buffer)
For the example from the comments, to tell this latter version to also skip all buffer names beginning with helm
, we could use:
(setq my-skippable-buffer-regexp
(rx bos (or (or "*Messages*" "*scratch*" "*Help*")
(seq "helm" (zero-or-more anything)))
eos))

- 50,977
- 3
- 79
- 122
Here are two ways:
If you take a look at the definition of function
switch-to-next-buffer
(in librarywindow.el
) you will see that it filters the buffers by the predicate (if any) that is the value of frame parameterbuffer-predicate
. That function is used bynext-buffer
.You can set that frame parameter to a predicate that filters the way you want.
You can simply advise function
switch-to-next-buffer
to filter the way you want. You will essentially replace its definition by almost the same definition, but filter additionally the way you want.
Similarly for switch-to-previous-buffer
.

- 6,150
- 1
- 15
- 26

- 77,472
- 10
- 114
- 243
You can as of 2022 (since Emacs 27.1?) achieve the same result as in the accepted answer with Emacs' built-in functionality, using switch-to-prev-buffer-skip
. For example, here is my current config (inspired by @phils' answer):
(defcustom aj8/buffer-skip-regexp
(rx bos (or (or "*Backtrace*" "*Compile-Log*" "*Completions*"
"*Messages*" "*package*" "*Warnings*"
"*Async-native-compile-log*")
(seq "magit-diff" (zero-or-more anything))
(seq "magit-process" (zero-or-more anything))
(seq "magit-revision" (zero-or-more anything))
(seq "magit-stash" (zero-or-more anything)))
eos)
"Regular expression matching buffers ignored by `next-buffer' and
`previous-buffer'."
:type 'regexp)
(defun aj8/buffer-skip-p (window buffer bury-or-kill)
"Return t if BUFFER name matches `aj8/buffer-skip-regexp'."
(string-match-p aj8/buffer-skip-regexp (buffer-name buffer)))
(setq switch-to-prev-buffer-skip 'aj8/buffer-skip-p)

- 156
- 3
helm*
buffers as well? – alper Aug 09 '20 at 23:51(seq "patter" (zero-or-more anything)
line? – alper Aug 10 '20 at 01:19(seq (or "helm" "foo" "bar") (zero-or-more anything))
to match a variety of prefixes. – phils Aug 10 '20 at 01:43.txt
? – alper Aug 15 '21 at 14:25(seq "helm" (zero-or-more anything))
is "all buffer names beginning withhelm
" then what's your guess at the equivalent "all buffer names ending with.txt
" ? – phils Aug 15 '21 at 14:36(anything zero-or-more)
? – alper Aug 15 '21 at 16:00(seq (zero-or-more anything) ".txt")
. The sequence of "zero-or-more of any character" followed by.txt
. Just like the earlier example was the sequence ofhelm
followed by "zero-or-more of any character". – phils Aug 15 '21 at 16:04*.txt
. I get confused when(zero-or-more anything)
is actually alias for*
. – alper Aug 15 '21 at 17:41(zero-or-more anything)
isrx
syntax for the regexp"\\(.\\|\n\\)*"
, with the trailing*
being the zero-or-more quantifier, and the preceding part matching any character. – phils Aug 16 '21 at 00:15.*
except that.
doesn't match newlines. – phils Aug 16 '21 at 03:38