到目前我们已经全面了解如何将一个函数定义为交互式命令并且将它绑定到一个快捷键上。现在我们来针对之前的内容做一个综合性的小练习
前期内容回顾
按照前面的规矩,我们先回顾一下之前涉及到的函数
首先可以通过在函数开始位置加入 interactive 来使一个函数变为一个可以由用户主动触发的交互式函数。
我们将交互式函数绑定到一个快捷键上,可以使用如下函数:
define-keyglobal-set-keylocal-set-key
以及Emacs 29以后提供了它们的替代版本:
keymap-setkeymap-global-setkeymap-local-setkeymap-unset
之后我们又介绍了如何将一个keymap 绑定到快捷键上,使快捷键成为一个前缀
make-sparse-keymapdefine-prefix-command
练习
本次练习也比较简单,我们也是围绕着快捷键的定义和绑定来。我们本次实现一些简单的vim方式的操作,我们实现一个名为 my-simple-vim-normal-mode 它对应着 vim 中的普通模式,我们可以通过 Esc 键来进入该mode,并且按i可以关闭该模式,O、o 可以分别在当前行的上一行和下一行插入新行并退出当前模式
基于这个目标我们可以先定义一些基本的快捷键和函数
(defvar my-simple-vim-normal-mode-map
(let ((map (make-sparse-keymap)))
(keymap-set map "h" #'backward-char)
(keymap-set map "l" #'forward-char)
(keymap-set map "j" #'next-line)
(keymap-set map "k" #'previous-line)
(keymap-set map "u" #'undo)
map))接着我们来实现快捷键的加载与卸载,这里我们使用 set-transient-map 来实现。它可以临时的启用一个全局最高等级的keymap。它可以接受一个keymap和一个函数。每一次用户按键并执行完对应的命令之后会执行这个函数,根据函数返回值来判断是否需要继续维持这个keymap。所以在进行切换的时候可以这么做:
(defvar-local my-simple-vim-normal-mode-active-p nil
"判断当前mode 是否处于激活状态")
(defun my/simple-vim-normal-mode-exit()
"退出当前mode"
(interactive)
(setq my-simple-vim-normal-mode-active-p nil))
(defun my/simple-vim-normal-mode-active()
"激活当前mode"
(interactive)
(setq my-simple-vim-normal-mode-active-p t)
(set-transient-map
my-simple-vim-normal-mode-map (lambda()
my-simple-vim-normal-mode-active-p)))最后我们绑定一个从当前模式进入vim 普通模式的快捷键,并且给出一些从vim普通模式退出的函数
(defun my/insert-new-line-next()
"当前行下方插入新空白行"
(interactive)
(goto-char (line-end-position))
(newline))
(defun my/insert-new-line-previous()
(interactive)
(forward-line -1)
(goto-char (line-end-position))
(newline))
;; 绑定使用 esc 激活该mode
;; 这里为了延续习惯绑定了 esc 键,但是在Emacs 中,捕获了esc键会导致meta键失效,读者如果可以考虑换一个键进行绑定
(global-set-key [escape] (lambda()
(interactive)
(if (not my-simple-vim-normal-mode-active-p)
(my/simple-vim-normal-mode-active))))
(keymap-set my-simple-vim-normal-mode-map "i" #'my/simple-vim-normal-mode-exit)
(keymap-set my-simple-vim-normal-mode-map "o" (lambda()
(interactive)
(my/insert-new-line-next)
(my/simple-vim-normal-mode-exit)))
(keymap-set my-simple-vim-normal-mode-map "O" (lambda()
(interactive)
(my/insert-new-line-previous)
(my/simple-vim-normal-mode-exit)))到此本篇的练习差不多结束了,读者如果有兴趣可以考虑再实现一些别的功能,进行填充,例如yy、p、v、A、I的绑定,使编辑器更趁手
评论 (0)