《elisp 每日一练》——Narrowing与Widen

《elisp 每日一练》——Narrowing与Widen

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

在前面我们介绍了Region的概念,它就是由 markerpoint 构成的一个区域。Region 是一种极度临时的状态——我们可以通过移动光标随时修改它的区域,或者激活/取消激活。

  • 光标可以随意移动出Region所在区域,以后如果基于这个条件进行操作时容易造成误操作
  • Region 可以说只有在激活那一刻才有效,后续如果改变了point 或者 marker 就会造成改变

为了应对这些问题,Eamcs中又有了 narrowingwiden 机制。它能将 Buffer 的可视与操作范围强制限制在特定区域内,为你提供一个安全、持久的局部编辑“沙盒”。

背景知识铺垫

Emacs 中允许我们通过 Narrowing 机制将注意力只集中在 Buffer 的某一部分,而把其余所有的文本暂时“隐身”。这样即使某些操作全局的函数此时也只能操作该范围内的文本。

首先,Narrowing 会改变 (point-max)(point-min) 的值,在默认没有 Narrwoing 的情况下, point-min 总是返回1,而 point-max 返回buffer中最后一个字符所在的索引。但一旦对 Buffer 施加了 Narrowing, point-minpoint-max 的值就与我们设置的可见区域的区间有关了。

我们可以通过 (narrow-to-region START END) 将buffer的可见区域设置为从 STARTEND之间的区域。通过 (widen) 来解除所有之前设置的 narrowing

实际上于 markpoint 类似,对于 Narrowing 我们也要考虑备份和恢复现场的情况,保存和恢复现场使用的函数是 save-restriction。在一些插件的代码中我们经常看到 save-restrictionsave-excursion 成对出现。它们的用法也是类似的。

既然它们一般是成对出现的,我们不妨考虑一下它们两个谁在外层,谁在内层呢?

假如 save-restriction 在外层,而 save-excursion 在内层, 也就是这样

;; 假设当前光标位于位置 (Point = 400)
(save-restriction
    (save-excursion
        (widen) ;; 暂时恢复可见区间为整个buffer
        (narrow-to-region (point-min) 200)
        (goto-char (point-max))
        ;; 执行其他操作
        ))

上述例子中,我们通过 narrow-to-region 将可见区域限制在 1200 这个区间。然后执行一些操作。当要恢复时先调用 save-excursion 尝试恢复光标位置到最初的 400时发现它的可见区域最多到200,此时光标位置可能被置于200位置。最后执行 save-restriction 恢复可见区域,但是此时光标已经回不到最初的 400位置了。

从上面可以看到最好是将 save-excursion 放在外层。

练习

本次的例子,我们实现一个简单的统计指定行中单词的个数。这次用到的函数为 count-words , 它的原形如下:

(count-words START END &optional TOTALS)

它主要接收两个参数:统计的起始位置和结束位置。

获取行的区间坐标可以通过 forword-line 移动光标到指定行,然后通过 line-beginning-positionline-end-position 获取行首和行尾位置的 point值

利用今天所学的内容可以写下如下的代码:

(defun my/count-words-in-line(line)
  ;; 获取行首和行尾位置
  (save-excursion
    (save-restriction
      (widen) ;; 先取消之前所设置的可见区间恢复整个buffer可见
      (goto-char (point-min))
      (forward-line (1- line)) ;; 移动到对应行
      (narrow-to-region (line-beginning-position) (line-end-position))
      (count-words (point-min) (point-max))
      )))

总结

本次我们了解了 Emacs 中的 Narrowing与Widen 机制。后面我们写代码操作文本时可以先直接默认操作整个区域,而在需要关注操作区间时通过 narrow-to-region 设置可见区间。不过不要忘了通过 save-restriction 恢复之前设置的可见区间。

本次我们介绍的api函数有:

  • narrow-to-region 设置可见区间
  • widen 取消之前设置的所有可见区间
  • save-restriction 恢复调用之前的可见区间
0

评论 (0)

取消