如何在Emacs中控制弹出buffer位置

缘起

org-agenda 是每天都要用的,如果不做设置的话,有时会在下部打开,因此需要做一定的配置才可以在右侧打开。原先我抄到的配置是:

(setq split-height-threshold nil)
(setq split-width-threshold 0)

split-height-thresholdsplit-width-threshold 这两个变量来控制窗口切分的行为。如果这两个变量的值是一个整数,比如默认值是80和160,则表示,如果当前窗口高度大于80行,则水平切分,如宽度大于160列,则垂直切分。如果这个值是nil,则表示永远不在水平或垂直方向切分。

这种做法是强制将所有的buffer都在垂直切分,并在右侧打开。这就造成了插入日期的 Calendar buffer也在右侧打开,这就比较难看。其实有更精确的控制方法。

使用 display-buffer-alist 来控制buffer的行为

在: https://emacs-china.org/t/org-capture-buffer/24645/6 中,有人提问如何设置 org-capture 弹出的位置,Pygmalion 提出了解决方案:

控制org capture弹出的org select 和 capture 这两个buffer的大小和位置有以下三种解决方案。

  1. 配置display-buffer-alist变量,可同时控制两个buffer的位置和大小,无需安装插件。配置如下:
(add-to-list 'display-buffer-alist
	       '("*Org Select*"
		 (display-buffer-in-side-window)
		 (window-height . 0.4)
		 (side . bottom))
	       '("CAPTURE-*"
		 (display-buffer-in-side-window)
		 (window-height . 0.4)
		 (side . bottom)))

可以让Org Select和Capture buffer都弹出在bottom。

  1. 配置display-buffer-alist变量控制org select buffer位置,配置split-width-threshold变量控制capture buffer位置(但不能控制其大小)
;; 控制 org select buffer

(add-to-list 'display-buffer-alist
	       '("*Org Select*"
		 (display-buffer-in-side-window)
		 (window-height . 0.4)
		 (side . bottom)))

;; 控制 org capture buffer

(setq split-width-threshold nil)
  1. 安装popper插件,可控制两个buffer的位置,大小无法控制,配置代码如下:
(use-package popper
    :ensure t ; or :straight t

    :bind (("C-`"   . popper-toggle-latest)
	   ("M-`"   . popper-cycle)
	   ("C-M-`" . popper-toggle-type))
    :init
    (setq popper-reference-buffers
	  '(("\\*Org Select\\*" org-mode)
	    ("CAPTURE" org-mode)
	    ))
    (popper-mode +1)
    (popper-echo-mode +1))

我用的第二种方案。第一个方案里的condition我试了下写combined condition不起作用,只好分别写了两段代码。

配置分析

可以看出,这个配置其实中是 display-buffer-alist 进行了定义,其中第一行,如 '("CAPTURE-*" 表示,这个定义针对的buffer范围,比如这个就针对 Capture buffer的。

(side . bottom) 表示新窗口打开的位置,这里就是在下方打开,当然也可以是 left 或 right

(window-height . 0.4) 表示这个窗口的大小,这里表示窗口高度是整个窗口的40%。如果你定义了左右侧打开的话,那么就要定义 window-width 了。

解决方案

如果按照上面的配置设置会出现一个问题,就是新开的buffer是以当前frame的side window的形式打开的,它无法单独的存在。即,如果光标在agenda的一个todo任务中,此时如果按 t 它会关闭其它buffer并让你选择要修改的 todo 状态。但如果是side window的话,会提示:“delete-other-windows: Cannot make side window the only window”

想到 org-roam 也有类似的配置来控制 org-roam-buffer 的行为,查看了后,它使用的是 (display-buffer-in-direction),并不会出现上述问题。除了这两个显示行为外,也可以自行 C-h f 查找 display-buffer 查看所有的显示行为。

回到最初的需求,想让 Org Agenda 在右侧打开,可以加上如下配置:

(add-to-list 'display-buffer-alist
	       '("Org Agenda"
		 (display-buffer-in-direction)
		 (window-width . 0.5)
		 (direction . right)))
海上一民工

Related