《elisp 每日一练》——跨 Buffer 文本提取

《elisp 每日一练》——跨 Buffer 文本提取

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

在之前的文章中,我们通过with-current-bufferbuffer-substring 实现了一个从指定buffer中拷贝文本到本buffer的功能。这个算是我们入门了跨buffer操作。实际上Emacs为这种需求提供了专门的函数

背景知识

Emacs中的跨buffer文本操作的基础函数是 (insert-buffer-substring BUFFER &optional START END) 。它用于将参数中 BUFFER 指定的缓冲区中从 STARTEND 这个范围内的文本插入到当前缓冲区的光标所在位置。我们可以用下面的代码感受一下

(defun my/copy-messages-buffer-to-this()
  (interactive)
  (let ((message-buffer (get-buffer "*Messages*")))
    (when message-buffer
      (let ((start)
        (end))
    (with-current-buffer message-buffer
      (save-restriction
        (widen)
        (setq start (point-min))
        (setq end (point-max))))
    (insert-buffer-substring message-buffer start end)))))

因为 STARTEND 参数实际上是对应的是 BUFFER 中的范围。所以我们需要切入到对应的buffer中去获取这个坐标的最大和最小值。

基于这个函数我们可以实现很多好用的跨buffer的文本操作,例如将当前buffer中的内容拷贝到目标buffer中,或者将目标buffer中的内容替换为我们想要的内容等等。

因为各种跨buffer的文本操作实在是太频繁了,所以Emacs提供很多有用的函数,下面我列举一些常用的函数

  • append-to-buffer: 从当前buffer中提取 STARTEND 范围内的文本并追加到参数 BUFFER 所指定的缓冲区的光标位置
  • copy-to-buffer : 从当前 buffer 中提取 STARTEND 范围内的文本并对参数中 BUFFER 所指定的缓冲区进行替换

上述这些函数提取的内容都带有文本属性,如果我们只想提取文本本身,可以使用 buffer-substring-no-properties

查阅相关文档,我们发现 buffer-substring-no-properties 实际上对标的是 buffer-substring,都是提取当前buffer的文本,而不涉及到改变buffer。在跨buffer的函数中,只有 insert-buffer-substring 是使用底层C函数编写的代码,而其他两个都是依靠这个函数,在lisp层面实现的。所以说,关于跨buffer的文本操作,我们只需要掌握基本的 insert-buffer-substring 其他的函数我们可以自己实现。这有点像数学,上学的时候老师告诉我初中的几何只有三条基本公理,其他的定理和自己利用这三条推导出来。Emacs也是这样,只提供基本的功能,其余高级的功能可以自己利用基本函数实现出来。但是也提供了这些高级函数的官方实现。

练习

今天我们来实现一个日志收集的功能。我们将当前用户选中的行记录到一个名为 Log-Collection 的buffer中,该buffer平时不允许写入,只能通过调用特定的函数进行收集。如果用户选择并激活了一个区间,则提取区间的内容进行激活,否则提取当前所在行的文本。

(defun my/collection-log()
  (interactive)
  (let ((log-buffer (get-buffer-create "*Log-Collection*"))
    (cur-buf (current-buffer))
    (start)
    (end))
    (if (use-region-p)
    ;; 激活了选区,则按照选取来决定范围
    (progn
      (setq start (region-beginning))
      (setq end (region-end)))
      ;; 未激活选取,则按照光标所在行来决定范围
      (progn
    (setq start (line-beginning-position))
    (setq end (line-end-position))))
    (with-current-buffer log-buffer
      (let ((inhibit-read-only t))
    (goto-char (point-max))
    (insert-buffer-substring cur-buf start end)))))

总结

本节介绍的重点函数只有一个 insert-buffer-substring 因为功能导致它的参数比较割裂,BUFFER 是目标buffer、而STARTEND 对应着源buffer的位置。这也就意味着想要成功调用该函数,无论如何都得使用 with-current-buffer 进行buffer的切换,无法一步到位

其余的函数我们可以自己实现,所以就不在这里列举了。

0

评论 (0)

取消