让emacs的next-buffer命令跳过*Messages*缓冲区

11

我想简单地修改Emacs,使得next-bufferprevious-buffer命令(我将它们绑定到C-x <RIGHT>C-x <LEFT>)可以跳过*Messages*缓冲区。

我正在使用Emacs 24和Emacs Starter Kit

我已经阅读了以下相关的问题和答案,但它们并不是我想要的:

以下是它们不起作用的原因:

  • 我希望尽可能保持简单。更少的配置更好。
  • 我不想完全杀死或防止*Messages*
  • (add-to-list 'ido-ignore-buffers "^\*Messages\*"可以帮助我使用C-x b (ido-switch-buffer),但它不会改变next-bufferprevious-buffer的行为。

我认为你应该看一下IDO。这不是一个答案,而是建议,因为(C-x <RIGHT>)xN比C-x b <RIGHT> xN不方便得多。 - desudesudesu
我建议读者参考http://emacs.stackexchange.com/q/17687/454(这是更近期的)。 - phils
4个回答

16

这样您就可以避免无限循环:

(defun next-code-buffer ()
  (interactive)
  (let (( bread-crumb (buffer-name) ))
    (next-buffer)
    (while
        (and
         (string-match-p "^\*" (buffer-name))
         (not ( equal bread-crumb (buffer-name) )) )
      (next-buffer))))
(global-set-key [remap next-buffer] 'next-code-buffer)

这段代码循环遍历非星号缓冲区("^\*")。对于您的情况(仅避免 *Messages*),它应该是:

(defun next-code-buffer ()
  (interactive)
  (let (( bread-crumb (buffer-name) ))
    (next-buffer)
    (while
        (and
         (equal "*Messages*" (buffer-name))
         (not ( equal bread-crumb (buffer-name) )) )
      (next-buffer))))
(global-set-key [remap next-buffer] 'next-code-buffer)

你可以把next-buffer替换成previous-buffer,从而写出previous-code-buffer


2
谢谢,*Helm...* 缓冲区真的让我很烦。 - CodyChan
这段代码经常卡住,我不会使用它...不太确定原因...我修复后会添加我的解决方案。 - ftravers

7
我能想到的最简单的方法是为两个函数都定义一个advice。下面是next-buffer的advice。类似的,还可以为previous-buffer定义一个advice。您还可以定义一个配置变量来启用/禁用此行为(或激活/停用advice)。
(defadvice next-buffer (after avoid-messages-buffer-in-next-buffer)
  "Advice around `next-buffer' to avoid going into the *Messages* buffer."
  (when (string= "*Messages*" (buffer-name))
    (next-buffer)))

;; activate the advice
(ad-activate 'next-buffer)

也许你可以通过其他方式比较缓冲区而不是其字符串名称,但那也可以工作。前一个缓冲区的代码几乎相同。我也不知道是否有一种方法可以在通知中调用原始函数而不触发通知本身,但同样,即使之后测试缓冲区的名称(如果只有一个缓冲区且它是消息缓冲区,则会失败;某些代码可以检查是否只有一个缓冲区并不再调用 next-buffer),该代码也可以工作。
如果您想使用执行相同操作的独立功能:
(defun my-next-buffer ()
  "next-buffer, only skip *Messages*"
  (interactive)
  (next-buffer)
  (when (string= "*Messages*" (buffer-name))
      (next-buffer)))

(global-set-key [remap next-buffer] 'my-next-buffer)
(global-set-key [remap previous-buffer] 'my-next-buffer)

5
如果你不能控制调用某些函数的人,我建议不要使用defadvice。在这种情况下,最好定义新函数并将其绑定到相关按键上,以确保不会出现意外的副作用。 - Lindydancer
嗯...也许你是对的,但是OP特别要求更改这些函数的工作方式。而且这就是defadvice的用途,对吧?无论如何,重新定义键绑定也是另一个可行的选择。 - Diego Sevilla
我很乐意调整我的按键绑定以指向新的函数。 - David J.
@DavidJames 答案已更新,新增了函数和绑定。对于互补版本,请使用“previous/left”进行重复和替换。 - Trey Jackson
1
@DiegoSevilla defadvice 不适用于此,尽管维基百科中有滥用它的例子。 defadvice 是一把非常锋利的危险刀具,应该保留给特殊工作使用。 [remap <command>] 绑定是为了解决这个问题而设计的。 - event_jr

6

这是我正在使用的,基于Diego的回答:

(setq skippable-buffers '("*Messages*" "*scratch*" "*Help*"))

(defun my-next-buffer ()
  "next-buffer that skips certain buffers"
  (interactive)
  (next-buffer)
  (while (member (buffer-name) skippable-buffers)
    (next-buffer)))

(defun my-previous-buffer ()
  "previous-buffer that skips certain buffers"
  (interactive)
  (previous-buffer)
  (while (member (buffer-name) skippable-buffers)
    (previous-buffer)))

(global-set-key [remap next-buffer] 'my-next-buffer)
(global-set-key [remap previous-buffer] 'my-previous-buffer)

目前还不够完美,因为除了我列出的可跳过的缓冲区以外,如果没有其他缓冲区,它就会挂起。当发生这种情况时,我使用 C-g 来打破循环,作为一种临时解决方法。


1
这应该被接受为答案,因为它处理可跳过缓冲区列表。 - rkm

2
如RubenCaro的回答所指出的,其他答案可能会进入无限循环。我认为David James的可跳过缓冲区列表方法更好一些,因此这里是该方法的一个变体。
(setq my-skippable-buffers '("*Messages*" "*scratch*" "*Help*"))

(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 ()
  "`next-buffer' that skips `my-skippable-buffers'."
  (interactive)
  (my-change-buffer 'next-buffer))

(defun my-previous-buffer ()
  "`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)

请使用稍微改进的形式在http://emacs.stackexchange.com/a/17694/454上重现此内容-请使用该版本而不是此版本(通常情况下,您最好使用该*问题*而不是此问题,因为这里的几个答案,包括被接受的答案,都相当有缺陷)。 - phils

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接