《elisp 每日一练》——minibuffer输入读取和set-transient-map 临时热键状态机

我们在前面介绍了 completing-read 给用户提供选项,让用户输入,但是如何处理这种需要用户主动输入的情况呢?本节我们将介绍一些主动读取用户输入的接口,然后补充一个我们在前面练习中涉及到的函数 set-transient-map

背景知识

completing-read 主要是提供几个候选项供用户选择,有点类似一般GUI程序的下拉列表框。而我们今天介绍的 read-from-minibuffer 就像GUI程序中的文本框。

它的函数签名如下:

emacs-lisp 复制代码
(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

emacs-lisp 复制代码
(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` 或任意其他键退出

我们先定义这些功能的函数

```emacs-lisp
(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,将这些操作进行绑定

emacs-lisp 复制代码
(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))

最后我们绑定一个快捷键进入该模式

emacs-lisp 复制代码
(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
相关推荐
Masimaro3 天前
《elisp 每日一练》—— Major Mode 管理 abbrev-table
emacs
AI情绪识别开源4 天前
检信AI学业生涯智选系统技术方案概述
emacs
Masimaro8 天前
《elisp 每日一练》—— Minor Mode 回顾与综合练习
emacs
aluluka8 天前
《elisp 每日一练》——状态栏显示管理与modeline 动态更新
emacs·lisp·elisp
aluluka9 天前
《elisp 每日一练》——minor mode 快捷键管理
emacs·lisp·elisp
Masimaro9 天前
《elisp 每日一练》——状态栏显示管理与modeline 动态更新
emacs
Masimaro12 天前
《elisp 每日一练》——minor mode 开关变量的管理
emacs
Masimaro13 天前
《elisp 每日一练》—— Minor Mode 变量生成机制与状态控制
emacs
Masimaro13 天前
《elisp 每日一练》——文件与目录的回顾与综合练习
emacs