- 1 课程回顾
- 2 概述
- 3 shackle 窗口行为控制
- 4 popper 窗口弹出行为管理
- 5 winner 窗口布局恢复
- 6 结语
1 课程回顾 🔗
通过上节课的学习,我们了解到如何在 Emacs 里使用 shell,尤其是 eshell,非常方便好用,我们可以在 Emacs 里快速进入 eshell 执行一些命令,得到你想要的结果,在 eshell 里还支持 elisp 函数,着实非常方便。
今天我们学习在 Emacs 里的窗口管理。
2 概述 🔗
在第一节课里,我们谈到了 Emacs 的一些基本概念,如 buffer, frame, window 等,这里我们再次温习一下 frame 和 window 的概念:
- frame
- 窗体,Emacs的整个窗口。
- window
- 分屏,Emacs在一个窗口内创建的多个分屏。
比如下图就是在一个窗体内部的2个分屏:
针对 frame,我们可以有很多命令和快捷键,如 make-frame
(s-n):
今天主要讨论的是对 window 的管理。
3 shackle 窗口行为控制 🔗
我们可以通过 shackle 插件来自定义窗口的弹出行为,主要有:方向、大小、弹出方式等等。
先来安装和配置它:
(use-package shackle
:ensure t
:hook (after-init . shackle-mode)
:init
(setq shackle-lighter "")
(setq shackle-select-reused-windows nil) ; default nil
(setq shackle-default-alignment 'below) ; default below
(setq shackle-rules
;; CONDITION(:regexp) :select :inhibit-window-quit :size+:align|:other :same|:popup
'((compilation-mode :ignore t)
("\\*Async Shell.*\\*" :regexp t :ignore t)
("\\*corfu.*\\*" :regexp t :ignore t)
("*eshell*" :select t :size 0.4 :align t :popup t)
(helpful-mode :select t :size 0.6 :align right :popup t)
("*Messages*" :select t :size 0.4 :align t :popup t)
("*Calendar*" :select t :size 0.3 :align t :popup t)
("*info*" :select t :same t)
(magit-status-mode :select t :inhibit-window-quit t :same t)
(magit-log-mode :select t :inhibit-window-quit t :same t)
))
)
其中,最重要的就是 shackle-rules
这个变量的配置,这个变量的配置主要有下面几个方面:
- CONDITION
- 条件,即这一条规则适用于满足什么样的条件才生效。这个条件可以是正则表达式,可以是字符串,可以是模式,如上面的例子,
*eshell*
就是匹配到缓冲区名字是*eshell*
时生效。 - :select
- 控制弹出 window 后是否选中
- :inhibit-window-quit
- 按“q”退出时,不删除这个缓冲区
- :size
- 0-1之间的数,控制 window 的百分比宽度或高度,如0.5就是指一半的宽度或高度
- :align
- 弹出的 window 往哪里看齐,可以取值为 t, ’left, ‘right, ‘below, ‘above
- :other
- 如果当前 frame 有多个 window,是否复用另外一个 window
- :popup
- 弹出一个新的 window,而不是复用当前 window
- :same
- 不弹出 window,复用当前 window
- :ignore
- 禁止显示该窗口
当我们安装配置完 shackle
之前,我们打开 eshell
时,是直接覆盖当前 window,如下图:
当我们安装配置完 shackle
之后,我们再次打开 eshell
时,就变成了在下方以高度40%的方式打开一个新的 window,如下图:
4 popper 窗口弹出行为管理 🔗
popper 可以控制窗口的弹出行为,可以与 shackle 一起配合使用。我们先来安装配置它:
(use-package popper
:ensure t
:bind (("M-`" . popper-toggle-latest)
("M-<tab>" . popper-cycle)
("M-\\" . popper-toggle-type)
)
:init
(setq popper-reference-buffers
'("\\*Messages\\*"
"\\*Async Shell Command\\*"
help-mode
helpful-mode
occur-mode
pass-view-mode
"^\\*eshell.*\\*$" eshell-mode ;; eshell as a popup
"^\\*shell.*\\*$" shell-mode ;; shell as a popup
("\\*corfu\\*" . hide)
(compilation-mode . hide)
;; derived from `fundamental-mode' and fewer than 10 lines will be considered a popup
(lambda (buf) (with-current-buffer buf
(and (derived-mode-p 'fundamental-mode)
(< (count-lines (point-min) (point-max))
10))))
)
)
(popper-mode +1)
(popper-echo-mode +1)
:config
;; group by project.el, projectile, directory or perspective
(setq popper-group-function nil)
;; pop in child frame or not
(setq popper-display-function #'display-buffer-in-child-frame)
;; use `shackle.el' to control popup
(setq popper-display-control nil)
)
配置完后,我们打开 eshell
,可以看到左下角显示了 POP
的字样,我们按下 M-`
可以一键关闭/打开这个 window,而且,这个 window 的位置和高度都如我们在 shackle
插件设置的那样,非常方便:
5 winner 窗口布局恢复 🔗
最后介绍一个内置的 winner
插件,作为补充,我们可以通过 winner-undo
和 winner-redo
命令恢复或重做当前的窗口布局。我们先来安装和配置它:
(use-package winner
:ensure nil
:hook (after-init . winner-mode)
:commands (winner-undo winner-redo)
:config
(setq winner-boring-buffers
'("*Completions*"
"*Compile-Log*"
"*inferior-lisp*"
"*Fuzzy Completions*"
"*Apropos*"
"*Help*"
"*cvs*"
"*Buffer List*"
"*Ibuffer*"
"*esh command on file*"))
)
例如,当前的窗口布局如下,左边是 emacs-config.org
文件,显示配置,右上是 *message*
缓冲区,右下是编译缓冲区:
此时,如果我们不小心按下 C-x 1
将窗口都删除了,我们还想恢复之前的布局,就可以通过 winner-undo
命令来恢复:
6 结语 🔗
通过今天的学习,我们了解了如何在 Emacs 控制窗口的行为,它能进一步的提升我们使用 Emacs 的顺滑度和工作效率。
这节课的配置文件的快照见:emacs-config-l24.org
你也可以在 这里 查看最新的配置文件。