Emacs:选择多个区域并切换到反向



我知道在 gnu emacs 中有几个不同的软件包用于选择多个区域。我正在寻找一种选择多个区域的方法,对它们进行操作,然后选择先前标记的区域的反向,以便对它们进行操作。

例如,假设我在缓冲区中有以下数据:

Line A
Line B
Line C
Line D
Line E
Line F

我想做的是:

  1. 将行 A、C 和 E 标记为多个区域
  2. 对这些标记区域内的文本应用一些 elisp
  3. 告诉 emacs 切换标记和未标记的区域。现在,B、D 和 F 行应该是标记为多个区域的行
  4. 将一些其他 elisp 应用于这些其他区域中的文本

步骤 1、2 和 4 很简单,它们仅取决于我决定使用的多区域标记代码的选择。

但是第 3 步呢?是否有任何多区域标记包允许我切换到以前标记的反向?

你的问题是一般性的。我的答案可能适合其中的一部分,但可能不是全部。

  1. zones.el(请参阅区域(允许您跨多个缓冲区定义和操作文本的多个区域(实际上是多个区域(。 你可以用它们做这些事情:

    • 对它们进行排序。
    • 合并(
    • 合并(相邻或重叠区域(包括对它们进行排序(。
    • 如果他们团结起来,就补充他们。
    • 相交。
    • 将缓冲区缩小到列表中的区域 - 请参阅多重收缩。
    • 选择列表中的区域作为活动区域。在区域之间循环。
    • 搜索它们(它们首先自动合并(。为此,您需要库isearch-prop.el(请参阅 Isearch+(。
    • 突出显示
    • 和取消突出显示它们。(为此,您需要突出显示库(highlight.el(或库facemenu+.el(请参阅面部菜单+(。
    • 将活动区域添加到区域列表。
    • 将区域添加到区域列表,然后合并(合并(区域。
    • 从区域列表中删除区域。
    • 将一个区域变量克隆
    • 到另一个区域变量,以便克隆具有相同的区域。
    • 克隆区域变量,然后合并克隆的区域。
    • 书签中使区域列表变量持久化。使用书签在后续的 Emacs 会话中恢复它。为此,您需要库书签+。
  2. 库 Isearch+(包括isearch-prop.el(允许您搜索由zones.el定义的区域和由文本或叠加属性(任何属性(定义的区域,并且它有助于将属性应用于文本区域。

    • 您还可以搜索一组区域的补充,我认为这就是您的问题的真正内容。 在搜索过程中,可以选择将未搜索的区域变暗。
    • 您可以将各种"事物"搜索为区域。事物可以是你可以用语法定义的任何事物。它们包括通常的Emacs"事物",如果您使用库thingatpt+.el那么您可以轻松定义其他内容。
  3. 如果使用冰柱,则可以对缓冲区或文件中的一组搜索上下文使用冰柱搜索。您可以通过多种方式定义搜索上下文,包括使用正则表达式。在那里,您也可以搜索一组搜索上下文的补充。您可以使用匹配搜索上下文的增量缩小,并且在此过程中,您还可以使用补充来减去匹配集。


在您发表评论后更新 -

您显然希望补充非基本区域列表(我称之为">izone"(,每个区域都是一个数字作为标识符,后跟两个区域限制。(基本区域只有限制,没有标识符,函数zz-zones-complement返回基本区域的列表。

这就是我定义补码函数的方式:

(defun zz-complement-izones (izones &optional beg end)
  "Complement IZONES, which is a list like `zz-izones'.
Such a list is also returned, that is, zones that have identifiers."
  (zz-izones-from-zones
   (zz-zones-complement (zz-zone-union (zz-izone-limits izones nil t)))))

这仅在剥离区域标识符并合并区域后使用预定义的功能zz-zones-complement。 预定义的函数zz-izones-from-zones为区域标识符提供,使结果成为 izone 列表。

并且您需要一个函数将函数映射到区域列表上,并将其应用于列表中的每个区域 - 您的函数traverse-zones做什么。

这是此类映射函数的一个版本(未经测试(,它需要您正在使用的形式的区域,即 izone(具有数字标识符的区域(并在它们上映射一个 3 元函数。它类似于您的traverse-zones(但请参阅评论(:

(defun map-izones (function &optional izones)
  "Map 3-ary FUNCTION over IZONES.
FUNCTION is applied to the first three elements of each zone.
IZONES is a list like `zz-izones', that is, zones with identifiers."
  ;; Do you really want this?  It prohibits mapping over an empty list of zones.
  ;; (unless izones) (setq izones  zz-izones)
  (when (and (functionp function)  (zz-izones-p izones))
    (setq izones  (zz-unite-zones izones))
    (dolist (izone  izones) (funcall function (car izone) (cadr izone) (caddr izone)))))

这是一个(未经测试的(版本,它将二进制函数映射到区域列表上。列表中的区域可以是所有基本区域,也可以是所有 izone。 这对我来说似乎更有用,因为在这种情况下,标识符通常不是很有用。

(defun map-zones (function &optional zones)
  "Map binary FUNCTION over ZONES, applying it to the limits of each zone.
ZONES can be a list of basic zones or a list like `zz-izones', that
is, zones that have identifiers."
  (when (functionp function)
    (when (zz-izones-p zones)
      (setq zones  (zz-izone-limits zones nil 'ONLY-THIS-BUFFER)))
    (setq zones  (zz-zone-union zones))
    (dolist (zone  zones) (funcall function (car zone) (cadr zone)))))

希望这有帮助。

我刚刚发现了一个初步答案。我说"初步",因为我还没有做任何深入的测试。但是,"zones.el"包正式提供了我正在寻找的功能。

它创建选定区域的列表,称为"区域"。它提供了一个名为 zz-zones-complement 的函数,它将返回当前区域的"合并"列表的补充,可以按如下方式获取:(zz-zones-complement (zz-zone-union zz-izones)) .

我相信这将为我提供我正在寻找的所有功能。但是,如果我遇到任何问题,我会回来再次发布。

谢谢你,德鲁。

事实证明,区域最接近我需要的,尽管冰柱和 isearch+ 也都很有用。

至于区域,事实证明它的zz-zones-补码函数似乎没有返回正确的信息。

但是,我编写了自己的函数,我可以使用它来代替它。

我现在这样做是为了在以前通过 zones.el 添加的所有区域的补码上运行任意 lisp 代码......

(defun my-complement-zones (&optional zones)
  (unless zones
    (setq zones zz-izones))
  (zz-unite-zones 'zones)
  (let ((result ())
        (end (copy-marker (point-min)))
        (n 0)
        (a nil)
        (b nil))
    (dolist (item (reverse zones))
      (setq n (1+ n))
      (setq a (cadr item))
      (setq b (caddr item))
      (setq result (append (list (list n end a)) result))
      (setq end b))
    (when (< (marker-position end) (point-max))
      (setq result (append (list (list (1+ n) end (copy-marker (point-max)))) result)))
    result))
;; Each element has three values: an index followed by the start
;; and end markers for each region. To traverse this structure,
;; do the following ...
(dolist (region (my-complement-zones))
  (let ((idx (car region))
        (start (cadr region))
        (end (caddr region)))
    ;; At this point, "start" is a marker pointing to the
    ;; beginning of the given zone, and "end" is a marker pointing
    ;; its endpoint. I can use these for inputs to any region-aware 
    ;; elisp commands, or for any functions that I might want to
    ;; write which operate on each given region.
    ;;
    ;; ... etc. ...
  ))

。这是我写的一个函数,它将遍历区域列表并将 lambda 应用于每个区域。无论我们使用原始的 zz-izones 还是使用我的函数生成的补码,它都可以等效地工作:

;; Helper function
(defun funcallable (func)
  (and func
       (or (functionp func)
           (and (symbolp func)
                (fboundp func)))))
;; Traverse a list of zones such as zz-izones, and apply a lambda
;; to each zone in the list. Works equivalently with the output of 
;; `my-complement-zones'.
(defun traverse-zones (func &optional zones)
  (when (funcallable func)
    (unless zones
      (setq zones zz-izones))
    (zz-unite-zones 'zones) ;; not sure if this is really necessary
    (dolist (zone zones)
      (let ((i (car zone))
            (s (cadr zone))
            (e (caddr zone)))
        (funcall func i s e)))))

为了说明 zz-izones 和 zz-zones-补码输出之间的结构差异,下面是我在名为 "foo" 的缓冲区中创建的 zz-izones 结构的示例:

((4 #<marker at 1202 in foo> #<marker at 1266 in foo>) (3 #<marker at 689 in foo> #<marker at 1132 in foo>) (2 #<marker at 506 in foo> #<marker at 530 in foo>) (1 #<marker at 3 in foo> #<marker at 446 in foo>))

以下是(zz-zones-补 zz-izone(对于相同的 zz-izones 列表的样子......

((1 4) (#<marker at 1202 in foo> 3) (#<marker at 689 in foo> 2) (#<marker at 506 in foo> 1) (#<marker at 3 in foo> 1266)

请注意,zz-izones 中的每个条目都包含一个索引和两个标记。但是,在其补码中,每个条目要么是两个整数,要么是一个标记和一个整数。这些结构不是同构的。

附加信息

对于(zz-zone-union (zz-izone-limits zz-izones nil t))...

((#<marker at 3 in foo> #<marker at 446 in foo>) (#<marker at 506 in foo> #<marker at 530 in foo>) (#<marker at 689 in foo> #<marker at 1132 in foo>) (#<marker at 1202 in foo> #<marker at 1266 in foo>)

对于(zz-zones-complement (zz-zone-union (zz-izone-limits zz-izones nil t)))

((1 #<marker at 3 in foo>) (#<marker at 446 in foo> #<marker at 506 in foo>) (#<marker at 530 in foo> #<marker at 689 in foo>) (#<marker at 1132 in foo> #<marker at 1202 in foo>) (#<marker at 1266 in foo> 1266))

我想如果我将第一个条目中的"1"转换为(copy-marker (point-min)),将最后一项中的"1266"转换为(copy-marker (point-max)),我想我可以使用此补码......除非我正在处理特定情况,否则我处理的是标记还是点并不重要。

标记是理想的,因为这样我就可以在生成补码后更改缓冲区,并且我不必担心补码结构中的数字点值不再指向它最初指向的位置。

相关内容

  • 没有找到相关文章

最新更新