我们在前面介绍了 completing-read 给用户提供选项,让用户输入,但是如何处理这种需要用户主动输入的情况呢?本节我们将介绍一些主动读取用户输入的接口,然后补充一个我们在前面练习中涉及到的函数 set-transient-map
背景知识
completing-read 主要是提供几个候选项供用户选择,有点类似一般GUI程序的下拉列表框。而我们今天介绍的 read-from-minibuffer 就像GUI程序中的文本框。
它的函数签名如下:
(read-from-minibuffer PROMPT &optional INITIAL-CONTENTS KEYMAP READ HIST DEFAULT-VALUE)其中常用参数的含义如下:
PROMPT提示词INITIAL-CONTENTS预先填写的内容,后续可以修改READ如果为 t,会自动调用 Lisp Reader,将输入的文本直接解析为 Lisp 对象DEFAULT-VALUE当用户直接按回车时返回的字符串
该接口相对来说是一个偏底层的接口,如果程序预先指定用户输入数据的类型,可以选择一些相对上层的封装函数:
read-string读取纯文本read-number读取数字read-command读取一个命令read-file-name读取一个文件名read-directory-name读取一个目录名称
我们可以通过 read 作为前缀搜索类似的函数。
另外一个今天要补充的函数就是 set-transient-map
(set-transient-map KEYMAP &optional KEEP-PRED ON-EXIT)它会临时将对应的keymap挂起,在下一次按键之后,会调用 KEEP-PRED 参数绑定的函数返回值决定是否卸载keymap。它的函数返回值有三种情况:
nil执行一个命令后理解卸载,也就是一次性的t保持,直到下一次调用时该函数返回nil数字如果是数字值,保持激活状态,直到连续执行了指定次数的命令后自动卸载
练习
今天我们的练习,我们来实现一个快速的文本大小写与替换功能。它的功能如下:
- 利用region 选中一段文本
- 按
C-c t进入该模式,此时我们利用set-tranient-map挂载一个快捷键的keymap - 按
u将选中文本转为大写 - 按
l转为小写 - 按
c转为首字母大写(Captial) - 按
r调用read-string读取你要替换的字符串,然后替换选中区域 - 按
q或任意其他键退出
我们先定义这些功能的函数
(defun my/upcase-region()
"选中区域的文本转化为大写"
(interactive)
(when (use-region-p)
(upcase-region (region-beginning) (region-end))))
(defun my/downcase-region()
"选中区域文本转为小写"
(interactive)
(when (use-region-p)
(downcase-region (region-beginning) (region-end))))
(defun my/capitalize-region()
"选中区域首字母大写"
(interactive)
(when (use-region-p)
(capitalize-region (region-beginning) (region-end))))
(defun my/replace-region()
"替换选中区域的文本"
(interactive)
(when (use-region-p)
(let* ((old-text (buffer-substring (region-beginning) (region-end)))
(new-text (read-string (format "替换 '%s' 为:" old-text))))
(delete-region (region-beginning) (rregion-end))
(insert new-text))))然后我们可以定义一个keymap,将这些操作进行绑定
(defvar my/text-operator-transient-map
(let ((map (make-sparse-keymap)))
(keymap-set map "u" #'my/upcase-region)
(keymap-set map "l" #'my/downcase-region)
(keymap-set map "c" #'my/capitalize-region)
(keymap-set map "r" #'my/replace-region)
(keymap-set map "q" (lambda()
(interactive)
(set-transient-map nil)))
map))最后我们绑定一个快捷键进入该模式
(defun my/start-text-operate()
(interactive)
(if (use-region-p)
(set-transient-map my/text-operator-transient-map)
(message "请先选中一段文本")))
(keymap-global-set "C-c t" #'my/start-text-operate)小结
本篇我们介绍了如何读取minibuffer 中用户的输入,以及补充了一个关于快捷键绑定的额外函数。本节涉及到的函数有:
read-from-minibuffer以及基于该函数实现的read 系列函数set-transient-map
评论 (0)