Emacs:select 多个区域并切换到反向
Emacs: select multiple regions and switch to inverse
我知道 selectgnu emacs 中的多个区域有几个不同的软件包。我正在寻找的是 select 多个区域的方法,对它们进行操作,然后 select 先前标记区域的倒数,以便对它们进行操作。
举个例子,假设我在缓冲区中有以下数据:
Line A
Line B
Line C
Line D
Line E
Line F
我想做的是:
- 将 A、C 和 E 行标记为多个区域
- 对这些标记区域内的文本应用一些 elisp
- 告诉emacs 切换标记和未标记区域。现在,B、D 和 F 行应该是标记为多个区域的行
- 对这些其他区域内的文本应用一些其他的 elisp
步骤 1、2 和 4 很简单,它们仅取决于我决定使用的多区域标记代码的选择。
但是第 3 步呢?是否有任何多区域标记包可以让我切换到之前标记的反向?
我刚刚发现了一个初步的答案。我说 "preliminary",因为我还没有做任何深入的测试。但是,"zones.el" package 正式提供了我正在寻找的功能。
它创建了一个选定区域的列表,它称之为 "zones"。它提供了一个名为 zz-zones-complement
的函数,它将 return 当前区域的 "coalesced" 列表的补充,可以通过以下方式获得:(zz-zones-complement (zz-zone-union zz-izones))
.
我相信这将为我提供我正在寻找的所有功能。但是,如果遇到任何问题,我会回来并再次 post。
你的问题很笼统。我的回答可能适合其中的一部分,但可能不适合所有。
库 zones.el
(see Zones) 允许您跨多个缓冲区定义和操作文本的多个区域(实际上是多个区域)。你可以用它们做这些事情:
- 对它们进行排序。
- 合并(合并)相邻或重叠的区域(包括对它们进行排序)。
- 如果统一了就补上
- 将它们相交。
- 将缓冲区缩小到列表中的区域 - 请参阅 MultipleNarrowings。
- Select 列表中的区域作为活动区域。在区域之间循环。
- 搜索他们(他们先自动合并)。为此你需要图书馆
isearch-prop.el
(see Isearch+).
- 突出显示和取消突出显示它们。 (为此你需要 Highlight library (
highlight.el
) or library facemenu+.el
(see Facemenu+)。
- 将活动区域添加到区域列表。
- 将区域添加到区域列表,然后联合(合并)区域。
- 从区域列表中删除一个区域。
- 将一个区域变量克隆到另一个区域变量,因此克隆具有相同的区域。
- 克隆一个区域变量,然后合并克隆的区域。
- 在书签中使区域列表变量持久化。使用书签在后续 Emacs 会话中恢复它。为此,您需要库 Bookmark+.
库 Isearch+ (including isearch-prop.el
) lets you search both zones as defined by zones.el
和由文本或覆盖属性(任何属性)定义的区域,它有助于将属性应用于文本区域。
- 您还可以搜索一组区域的补充,我认为这才是您真正要问的问题。在搜索过程中,可以选择将未搜索的区域变暗。
- 您可以搜索各种 "THINGS" 作为区域。事物可以是任何你可以在语法上定义的东西。它们包括常用的 Emacs "things",如果您使用库
thingatpt+.el
,那么您可以轻松定义其他内容。
如果您使用 Icicles,那么您可以在缓冲区或文件中的一组 搜索上下文 上使用 Icicles 搜索。您可以通过多种方式定义搜索上下文,包括使用正则表达式。您也可以在其中搜索一组搜索上下文的 补充 。您可以使用增量缩小匹配搜索上下文,并且在这样做时您还可以使用补充来减去匹配集。
在您发表评论后更新 -
你显然想补充一个非基本区域列表(我称之为“izones”),每个区域都是数字作为标识符,后跟两个区域限制。 (基本区域只有限制,没有标识符,函数zz-zones-complement
returns基本区域列表。)
这就是我定义补函数的方式:
(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
的作用。
这是此类地图函数的一个版本(未经测试),它需要您正在使用的形式的区域,即 izones(具有数字标识符的区域)并在其上映射一个 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)))))
希望对您有所帮助。
谢谢你,德鲁。
事实证明zone最接近我需要的,虽然icicles和isearch+也很有用。
至于区域,事实证明它的 zz-zones-complement 函数似乎 return 不正确的信息。
但是,我编写了自己的函数,可以代替它使用。
我现在对 运行 以前通过 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-complement 的输出之间的结构差异,这里是我在名为 "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-izones 列表的 (zz-zones-complement 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))
,我想我可以使用这个补语……除非我我正在处理一个具体案例,在这个案例中,我处理的是标记还是点都无关紧要。
标记是理想的,因为这样我可以在生成补码后更改缓冲区,而且我不必担心补码结构中的数字点值不再指向它原来指向的位置。
我知道 selectgnu emacs 中的多个区域有几个不同的软件包。我正在寻找的是 select 多个区域的方法,对它们进行操作,然后 select 先前标记区域的倒数,以便对它们进行操作。
举个例子,假设我在缓冲区中有以下数据:
Line A
Line B
Line C
Line D
Line E
Line F
我想做的是:
- 将 A、C 和 E 行标记为多个区域
- 对这些标记区域内的文本应用一些 elisp
- 告诉emacs 切换标记和未标记区域。现在,B、D 和 F 行应该是标记为多个区域的行
- 对这些其他区域内的文本应用一些其他的 elisp
步骤 1、2 和 4 很简单,它们仅取决于我决定使用的多区域标记代码的选择。
但是第 3 步呢?是否有任何多区域标记包可以让我切换到之前标记的反向?
我刚刚发现了一个初步的答案。我说 "preliminary",因为我还没有做任何深入的测试。但是,"zones.el" package 正式提供了我正在寻找的功能。
它创建了一个选定区域的列表,它称之为 "zones"。它提供了一个名为 zz-zones-complement
的函数,它将 return 当前区域的 "coalesced" 列表的补充,可以通过以下方式获得:(zz-zones-complement (zz-zone-union zz-izones))
.
我相信这将为我提供我正在寻找的所有功能。但是,如果遇到任何问题,我会回来并再次 post。
你的问题很笼统。我的回答可能适合其中的一部分,但可能不适合所有。
库
zones.el
(see Zones) 允许您跨多个缓冲区定义和操作文本的多个区域(实际上是多个区域)。你可以用它们做这些事情:- 对它们进行排序。
- 合并(合并)相邻或重叠的区域(包括对它们进行排序)。
- 如果统一了就补上
- 将它们相交。
- 将缓冲区缩小到列表中的区域 - 请参阅 MultipleNarrowings。
- Select 列表中的区域作为活动区域。在区域之间循环。
- 搜索他们(他们先自动合并)。为此你需要图书馆
isearch-prop.el
(see Isearch+). - 突出显示和取消突出显示它们。 (为此你需要 Highlight library (
highlight.el
) or libraryfacemenu+.el
(see Facemenu+)。 - 将活动区域添加到区域列表。
- 将区域添加到区域列表,然后联合(合并)区域。
- 从区域列表中删除一个区域。
- 将一个区域变量克隆到另一个区域变量,因此克隆具有相同的区域。
- 克隆一个区域变量,然后合并克隆的区域。
- 在书签中使区域列表变量持久化。使用书签在后续 Emacs 会话中恢复它。为此,您需要库 Bookmark+.
库 Isearch+ (including
isearch-prop.el
) lets you search both zones as defined byzones.el
和由文本或覆盖属性(任何属性)定义的区域,它有助于将属性应用于文本区域。- 您还可以搜索一组区域的补充,我认为这才是您真正要问的问题。在搜索过程中,可以选择将未搜索的区域变暗。
- 您可以搜索各种 "THINGS" 作为区域。事物可以是任何你可以在语法上定义的东西。它们包括常用的 Emacs "things",如果您使用库
thingatpt+.el
,那么您可以轻松定义其他内容。
如果您使用 Icicles,那么您可以在缓冲区或文件中的一组 搜索上下文 上使用 Icicles 搜索。您可以通过多种方式定义搜索上下文,包括使用正则表达式。您也可以在其中搜索一组搜索上下文的 补充 。您可以使用增量缩小匹配搜索上下文,并且在这样做时您还可以使用补充来减去匹配集。
在您发表评论后更新 -
你显然想补充一个非基本区域列表(我称之为“izones”),每个区域都是数字作为标识符,后跟两个区域限制。 (基本区域只有限制,没有标识符,函数zz-zones-complement
returns基本区域列表。)
这就是我定义补函数的方式:
(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
的作用。
这是此类地图函数的一个版本(未经测试),它需要您正在使用的形式的区域,即 izones(具有数字标识符的区域)并在其上映射一个 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)))))
希望对您有所帮助。
谢谢你,德鲁。
事实证明zone最接近我需要的,虽然icicles和isearch+也很有用。
至于区域,事实证明它的 zz-zones-complement 函数似乎 return 不正确的信息。
但是,我编写了自己的函数,可以代替它使用。
我现在对 运行 以前通过 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-complement 的输出之间的结构差异,这里是我在名为 "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-izones 列表的 (zz-zones-complement 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))
,我想我可以使用这个补语……除非我我正在处理一个具体案例,在这个案例中,我处理的是标记还是点都无关紧要。
标记是理想的,因为这样我可以在生成补码后更改缓冲区,而且我不必担心补码结构中的数字点值不再指向它原来指向的位置。