29.20 窗口起始与结束位置

每个窗口都会维护一个标记(marker),用于追踪缓冲区中指定显示起始位置的位置。 该位置被称为窗口的 display-start 位置(或简称 start)。 此位置之后的字符会出现在窗口的左上角。 该位置通常(但并非必然)位于文本行的行首。

切换窗口或缓冲区之后,以及在某些其他情况下,如果窗口起始位置位于某一行中间, Emacs 会将窗口起始位置调整至该行行首。 这可以避免某些操作将窗口起始位置留在行内无意义的位置。 该特性可能会影响通过 Lisp 模式命令执行来测试某些 Lisp 代码,因为这些命令会触发上述调整。 若要测试此类代码,可将其封装为命令并绑定到按键上。

Function: window-start &optional window

该函数返回窗口 window 的显示起始位置。 若 windownil,则使用当前选中窗口。

创建窗口或在其中显示其他缓冲区时,显示起始位置会被设为该缓冲区最近使用过的显示起始位置; 若缓冲区无此记录,则设为 point-min

重绘会更新窗口起始位置(若自上一次重绘后未显式指定过),以确保点(point)显示在屏幕上。 除重绘外,没有其他操作会自动改变窗口起始位置; 移动点后,需等到下一次重绘完成,窗口起始位置才会相应变化。

Function: window-group-start &optional window

该函数与 window-start 类似,区别在于当 window 属于某个窗口组(see Window Group)时, window-group-start 会返回整个窗口组的起始位置。 当缓冲区局部变量 window-group-start-function 被设为某个函数时,该条件生效。 此时 window-group-start 会以 window 为唯一参数调用该函数,并返回其结果。

Function: window-end &optional window update

该函数返回 window 中缓冲区显示结束的位置。 window 默认为当前选中窗口。

仅修改缓冲区文本或移动点不会更新 window-end 的返回值。 该值仅在 Emacs 重绘且重绘未被中断完成时才会更新。

window 上一次重绘被中断并未完成,Emacs 无法得知该窗口的显示结束位置, 此时该函数返回 nil

update 为非 nilwindow-end 总会基于当前 window-start 返回最新的显示结束位置。 若之前保存的该位置值仍然有效,则直接返回;否则会扫描缓冲区文本计算出正确值。

即使 update 为非 nilwindow-end 也不会像真实重绘那样, 在点移出屏幕时尝试滚动显示,也不会修改 window-start 的值。 它仅报告在无需滚动时显示文本的结束位置。 注意:其返回的位置可能只是部分可见。

Function: window-group-end &optional window update

该函数与 window-end 类似,区别在于当 window 属于某个窗口组(see Window Group)时, window-group-end 会返回整个窗口组的结束位置。 当缓冲区局部变量 window-group-end-function 被设为某个函数时,该条件生效。 此时 window-group-end 会以 windowupdate 为参数调用该函数,并返回其结果。 参数 update 的含义与 window-end 中一致。

Function: set-window-start window position &optional noforce

该函数将 window 的显示起始位置设为其对应缓冲区中的 position 位置,并返回 position

显示逻辑要求缓冲区显示时点必须可见。 通常它们会按照内部逻辑选择显示起始位置(必要时滚动窗口)以保证点可见。 但如果你通过该函数指定起始位置并将 noforce 设为 nil, 则表示即使这会导致点移出屏幕,仍希望从 position 开始显示。 若点确实因此移出屏幕,显示逻辑会尝试将点移至窗口中间行的左边缘。

例如,若点位置为 1,而你将窗口起始位置设为 37(下一行开头), 点就会位于窗口顶部之外。 重绘时若点仍为 1,显示逻辑会自动移动点。示例如下:

;; 执行 set-window-start 表达式前 ‘foo’ 的显示

---------- Buffer: foo ----------
∗This is the contents of buffer foo.
2
3
4
5
6
---------- Buffer: foo ----------

(set-window-start
 (selected-window)
 (save-excursion
   (goto-char 1)
   (forward-line 1)
   (point)))
⇒ 37

;; 执行 set-window-start 表达式后 ‘foo’ 的显示
---------- Buffer: foo ----------
2
3
∗4
5
6
---------- Buffer: foo ----------

若尝试让点可见(即在完整可见的屏幕行内)失败, 显示逻辑会忽略指定的窗口起始位置并重新计算。 因此,调用该函数的 Lisp 程序若要获得可靠结果, 应始终将点移动到以 position 为显示起始的窗口可见范围内。

noforce 为非 nil,且 position 会导致下次重绘时点移出屏幕, 则重绘会结合点的位置重新计算合适的窗口起始位置,position 不会被使用。

Function: set-window-group-start window position &optional noforce

该函数与 set-window-start 类似,区别在于当 window 属于某个窗口组(see Window Group)时, set-window-group-start 会设置整个窗口组的起始位置。 当缓冲区局部变量 set-window-group-start-function 被设为某个函数时,该条件生效。 此时 set-window-group-start 会以 windowpositionnoforce 为参数调用该函数,并返回其结果。 参数 positionnoforce 的含义与 set-window-start 中一致。

Function: pos-visible-in-window-p &optional position window partially

position 位于 window 屏幕当前可见文本范围内,该函数返回非 nil; 若 position 因垂直滚动不可见,则返回 nil。 被部分遮挡的位置不视为可见,除非 partially 为非 nil。 参数 position 默认为 window 中点的当前位置;window 默认为选中窗口。 若 positiont,则检查 window 最后一行的首个可见位置或缓冲区结束位置,取先出现的一个。

该函数只考虑垂直滚动。若 position 仅因窗口水平滚动不可见,pos-visible-in-window-p 仍返回非 nil。 See 水平滚动

position 可见:当 partiallynil 时返回 t; 当 partially 为非 nilposition 之后的字符完全可见时, 返回形如 (x y) 的列表,其中 x、y 为相对于窗口左上角的像素坐标; 否则返回扩展列表 (x y rtop rbot rowh vpos), 其中 rtop、rbot 为该行顶部与底部超出窗口的像素数,rowh 为该行可见高度,vpos 为该行垂直位置(从零开始的行号)。

示例:

;; 若当前点不在屏幕内,立即居中显示
(or (pos-visible-in-window-p
     (point) (selected-window))
    (recenter 0))
Function: pos-visible-in-window-group-p &optional position window partially

该函数与 pos-visible-in-window-p 类似,区别在于当 window 属于某个窗口组(see Window Group)时, pos-visible-in-window-group-p 会检测位置在整个窗口组中的可见性,而非仅在单个窗口中。 当缓冲区局部变量 pos-visible-in-window-group-p-function 被设为某个函数时,该条件生效。 此时 pos-visible-in-window-group-p 会以 positionwindowpartially 为参数调用该函数,并返回其结果。 参数 positionpartially 的含义与 pos-visible-in-window-p 中一致。

Function: window-line-height &optional line window

该函数返回 window 中第 line 行文本的高度。 若 lineheader-linemode-line,则返回窗口对应行的相关信息。 否则 line 为从 0 开始的文本行号,负数表示从窗口末尾计数。 line 默认为 window 中的当前行;window 默认为选中窗口。

若显示并非最新状态,window-line-height 返回 nil, 此时可使用 pos-visible-in-window-p 获取相关信息。

若不存在指定行,window-line-height 返回 nil。 否则返回列表 (height vpos ypos offbot), 其中 height 为该行可见部分的像素高度,vposypos 为该行相对于首行文本的垂直位置(行数与像素), offbot 为该行底部超出窗口的像素数。 若首行文本顶部有超出窗口的像素,ypos 为负数。