11

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.

8

Here are two ways:

  1. If you take a look at the definition of function switch-to-next-buffer (in library window.el) you will see that it filters the buffers by the predicate (if any) that is the value of frame parameter buffer-predicate. That function is used by next-buffer.

    You can set that frame parameter to a predicate that filters the way you want.

  2. 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.

| improve this answer | |
10
(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))
| improve this answer | |
  • What should I do to hide all helm* buffers as well? – alper Aug 9 at 23:51
  • yes it does! Thanks @phils – alper Aug 10 at 0:12
  • I've updated the answer accordingly. Please test. – phils Aug 10 at 0:56
  • With the current updated code it works without a problem. If I add new patterns would I just add (seq "patter" (zero-or-more anything) line? – alper Aug 10 at 1:19
  • 1
    You can do, but I would suggest using (seq (or "helm" "foo" "bar") (zero-or-more anything)) to match a variety of prefixes. – phils Aug 10 at 1:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.