在前面关于buffer 的介绍中,我们都是在操作当前buffer。但是Emacs里面有许多buffer,同时也允许我们创建不同的buffer。本篇我们将进入buffer操作的环节。看看如何在Emacs中管理buffer。
背景知识
buffer的操作与文本操作类似,无外乎也就是增删改查四个大的内容。我们按照这个顺序来介绍。
首先是buffer的创建,可以使用 get-buffer-create 来完成,它接收一个buffer 名称的字符串作为参数,如果当前名称的buffer已经存在则直接获取该buffer的对象,否则创建一个新的buffer。如果我们无论如何都要创建新buffer,而不管名称是否存在,可以使用 generate-new-buffer,该函数会无条件的创建新的buffer,如果当前名称的buffer已经存在,它会创建一个带数字后缀名称的新buffer。而如果我们仅仅获取已经存在的buffer,可以通过函数 get-buffer,当buffer不存在时会返回nil
删除一个buffer 可以使用 kill-buffer,它接收一个buffer对象或者buffer名称的字符串作为参数,来删除一个buffer。
修改buffer,实际上我个人认为分成两个层面,一个是修改buffer的内容,也就是前面我们提到的goto-char、delete-region 之类的文本操作。而另一个就是修改buffer的属性。其中有一个就是修改当前buffer,在这个层面可以使用函数 set-buffer。
这里可能要稍微补充一下什么是当前缓冲,用面向对象的角度来讲,我们调用操作对象的方法总的有一个被操作的对象,而C/C++ 中这个对象实际上通过类函数中的this 指针进行绑定。而我们调用 goto-char、insert、delete-region 等函数,操作的是当前buffer,如果我们希望这些函数操作另外的buffer,那么就需要通过 set-buffer 修改默认buffer。
一般来讲,我们通过 set-buffer 切换到别的buffer中进行操作实际上是一个临时性的动作,因为用户此时的注意力完全在当前显示的buffer上,我们只会短暂的切换,而后续又会切换回来。因此这里涉及到一个关于buffer的保存和恢复现场的概念。保存和恢复buffer的现场,用的是 with-current-buffer。
witch-current-buffer 会切换到一个已存在的buffer,而事后并不会主动清理无效的buffer。也是说我们在使用前要先确保当前buffer存在,然后使用。但是有时候我们仅仅只需要一个临时的buffer,用后直接删除,此时可以使用 with-temp-buffer
到此为止我们已经有4个保存和恢复现场的函数了。我们一般的顺序是 with-current-buffer、save-excursion、save-restriction,至于 save-match-data ,用的不如前面一个广泛。
查询buffer,我们可以通过 buffer-name 获取指定buffer的名称,它接收一个buffer对象,或者默认获取当前buffer的名称。我们也可以通过 buffer-list 来获取所有buffer 的列表。
最后我们判断一个buffer是否有效时可以使用 buffer-live-p
练习
buffer的内容可能没有之前介绍文本操作时那么详细,因为我觉得buffer比较简单,实际上我们只要理解buffer是Emacs存放文本的一个内存缓冲区,我们的这些操作实际上就是在修改保留这块内存的变量的属性。而且如果读者对一些文本编辑器有一定的了解,会发现大多数文本编辑器都有buffer的概念。
本次的练习我们来尝试将用户选定的buffer中的文本拷贝到当前buffer最后面。它经历的流程如下:
- 通过交互式命令让用户输入对应的buffer名称
- 通过名称获取buffer对象,如果对象不存在则输出错误信息
- 切换当前buffer
- 直接通过 buffer-substring 获取整个buffer的拷贝
- 切换回当前buffer
- 调用insert插入对应的文本
最终我实现的代码如下:
(defun my/append-string-to-buffer(bname)
(interactive "B您要拷贝哪个buffer的内容:")
(let ((src-buffer (get-buffer bname)))
(if src-buffer ;; buffer有效
(let (src-string)
(with-current-buffer src-buffer
(save-restriction
(widen)
(setq src-string (buffer-substring (point-min) (point-max)))))
(push-mark)
(goto-char (point-max))
(newline)
(insert src-string))
(message "无效的buffer名称"))))当前例子中的代码还是有一些问题的,例如我们没有判断当前所在的buffer是否是只读类型的。只读类型只是buffer的一个属性,关于buffer中的相关属性将在后面的内容进行讨论。
本篇我们介绍的函数如下:
get-buffer-creategenerate-new-bufferget-bufferkill-bufferset-bufferwith-current-bufferwith-temp-bufferbuffer-namebuffer-listbuffer-live-p
评论 (0)