《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 每日一练》——Window 树与布局状态恢复
emacs
典典分享指南5 天前
Windows 自动化踩坑实录
python·intellij-idea·pyqt·emacs·visual studio
辰辉创聚6 天前
重组细胞因子全解析:定义、分类与应用指南
人工智能·eclipse·emacs·白细胞介素·重组蛋白·重组细胞因子
Masimaro8 天前
《elisp 每日一练》—— 前缀按键
emacs
带娃的IT创业者11 天前
Emacs 31:一场静默而深刻的范式演进
编辑器·文本编辑器·开源软件·emacs·lisp·软件架构
Masimaro13 天前
《elisp 每日一练》——syntax-table
emacs
Masimaro19 天前
《elisp 每日一练》—— overlay 机制
emacs
Masimaro22 天前
《elisp 每日一练》——buffer属性
emacs
2601_958548484 个月前
高频脉冲电源厂家选择:放心供应商筛选策略解析
emacs