《elisp 每日一练》——buffer 操作

《elisp 每日一练》——buffer 操作

Masimaro
2026-08-10 / 0 评论 / 1 阅读 / 正在检测是否收录...

在前面关于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-charinsertdelete-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-buffersave-excursionsave-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-create
  • generate-new-buffer
  • get-buffer
  • kill-buffer
  • set-buffer
  • with-current-buffer
  • with-temp-buffer
  • buffer-name
  • buffer-list
  • buffer-live-p
0

评论 (0)

取消