29.18 原子窗口

原子窗口是由至少两个活动窗口组成的矩形整体。它们具有以下显著特征:

这意味着所有修改窗口结构的基础函数都会把原子窗口当作一个整体对待,从而保留其内部布局。

原子窗口适用于构建并固定一些必须同时显示多个相关缓冲区的布局,例如显示文件版本差异、同一文本的不同语言/标记格式等。也可用于在某个窗口侧边固定显示与其相关的信息栏。

原子窗口依靠保留的窗口参数 window-atom(see 窗口参数)和一个被称为**原子窗口根窗口**的内部窗口(see Emacs 窗口的基本概念)实现。同一原子窗口内的所有窗口都以该根窗口为共同祖先,并且都被设置了非 nilwindow-atom 参数。

下列函数返回指定窗口所属原子窗口的根窗口:

Function: window-atom-root &optional window

该函数返回 window 所在原子窗口的根窗口。window 必须为有效窗口,默认为当前选中窗口。若该窗口不属于任何原子窗口,则返回 nil

创建原子窗口最简单的方式是对一个已有的内部窗口使用以下函数:

Function: window-make-atom window

该函数将 window 转为原子窗口。window 必须是一个内部窗口。其作用只是将 window 所有后代窗口的 window-atom 参数设为 t

若要从一个活动窗口创建原子窗口,或将新窗口加入已有原子窗口,可使用下面的缓冲区显示动作函数(see 缓冲区显示动作函数):

Function: display-buffer-in-atom-window buffer alist

该函数尝试在新窗口中显示 buffer,并将其与已有窗口组合为原子窗口。若该已有窗口已属于某个原子窗口,则将新窗口加入该原子窗口。

alist 为符号—值关联列表,以下符号具有特殊含义:

window

指定要与新窗口组合的已有窗口。若指定的是内部窗口,则其所有子窗口也会一并加入原子窗口。若未指定,则新窗口作为当前选中窗口的兄弟窗口。若该已有窗口是活动窗口且尚未设置 window-atom,则其 window-atom 会被设为 main

side

指定新窗口出现在已有窗口的哪一侧。有效值为 belowrightaboveleft,默认为 below。新窗口的 window-atom 参数会被设为此值。

返回值为新创建的窗口,创建失败则返回 nil

需要注意,window-atom 参数只要非 nil 即可,具体值并不重要。display-buffer-in-atom-window 设置的值只是为了方便后续识别原始窗口与新窗口。 另外,display-buffer-in-atom-window 只设置 window-atom 这一个窗口参数,其他窗口参数需要通过 alist 中的 window-parameters 条目显式指定。

当原子窗口的任意组成窗口被删除时,该原子窗口会自动解散。若要手动解散原子窗口,只需将其根窗口及所有后代窗口的 window-atom 参数重置即可。

下面这段代码在单窗口框架中执行时,会先分割选中窗口,以它们的父窗口为根创建原子窗口,然后在框架底部新开窗口显示 *Messages*,并将其加入该原子窗口。

(let ((window (split-window-right)))
  (window-make-atom (window-parent window))
  (display-buffer-in-atom-window
   (get-buffer-create "*Messages*")
   `((window . ,(window-parent window)) (window-height . 5))))

此时在该框架任意窗口中按 C-x 2 会在框架底部新开窗口;按 C-x 3 则在右侧新开窗口。 在原子窗口内任意窗口按 C-x 1 只会删除外部新窗口; 在原子窗口内按 C-x 0 会让新窗口占满整个框架。