在Emacs中是否有一个apply-function-to-region-lines函数?

9
我的很多工作都涉及搜索和删除不必要的代码行。因此,我创建了一个宏,然后选择所有行 (C-x h),然后运行命令 (apply-macro-to-region-lines)。我设法保存了该命令,并将其放置在我的 .emacs 文件中;我称之为 cut_it_now。但现在我的函数不再是宏,所以我不能再使用 (apply-macro-to-region-lines) 函数了。 你知道是否有实现了 (apply-function-to-region-lines) 的地方吗?
非常感谢,
D
5个回答

5
请注意,您仍然可以使用从代码生成的宏与apply-macro-to-region-lines一起使用,前提是该宏定义为向量或字符串。通过自定义的apply-named-macro-to-region-lines[2],您可以交互式地选择要使用的宏。
Emacs有两种从键盘宏生成代码的方法,具体取决于用于命名的方法。
如果您使用kmacro-name-last-macro(绑定到C-xC-kn),则Emacs会从宏生成一个函数,这对于此特定目的不是直接有用的[1]。
如果您使用name-last-kbd-macro来命名您的宏,则它将被生成为向量或字符串。
在任一情况下,然后使用insert-kbd-macro来获取代码。
实际上,向量/字符串格式是默认格式,因此您可以跳过命名步骤,立即请求代码(在名称提示处键入RET以指示最近定义的宏),然后手动编辑插入代码的默认名称。
[1]: 向量形式似乎只是嵌入在函数定义中,因此您应该能够从代码中提取它,以手动重新定义向量格式的宏函数。
[2]: 当我最初撰写此答复时,我忘记了这是一个自定义函数。对此我感到抱歉。
(defun apply-named-macro-to-region-lines (top bottom)
  "Apply named keyboard macro to all lines in the region."
  (interactive "r")
  (let ((macro (intern
                (completing-read "kbd macro (name): "
                                 obarray
                                 (lambda (elt)
                                   (and (fboundp elt)
                                        (or (stringp (symbol-function elt))
                                            (vectorp (symbol-function elt))
                                            (get elt 'kmacro))))
                                 t))))
    (apply-macro-to-region-lines top bottom macro)))

5
以下函数应该能够满足您的需求:
(defun apply-function-to-region-lines (fn)
  (interactive "aFunction to apply to lines in region: ")
  (save-excursion
    (goto-char (region-end))
    (let ((end-marker (copy-marker (point-marker)))
          next-line-marker)
      (goto-char (region-beginning))
      (if (not (bolp))
          (forward-line 1))
      (setq next-line-marker (point-marker))
      (while (< next-line-marker end-marker)
        (let ((start nil)
              (end nil))
          (goto-char next-line-marker)
          (save-excursion
            (setq start (point))
            (forward-line 1)
            (set-marker next-line-marker (point))
            (setq end (point)))
          (save-excursion
            (let ((mark-active nil))
              (narrow-to-region start end)
              (funcall fn)
              (widen)))))
      (set-marker end-marker nil)
      (set-marker next-line-marker nil))))

所以,如果您有以下要应用于缓冲区行的函数:
(defun test()
  (insert "> "))

而且,如果您的缓冲区包含以下内容:

Line 1: blah, blah
Line 2: blah, blah
Line 3: blah, blah
Line 4: blah, blah

如果您选择包含第2行和第3行的区域,则在提示输入函数名称时输入“test”,并输入“M-x apply-function-to-region-lines”,则会在缓冲区中得到以下结果:
Line 1: blah, blah
> Line 2: blah, blah
> Line 3: blah, blah
Line 4: blah, blah

你为什么要缩短每一行代码? - ceving

4
一个简单的解决方案是定义一个宏来调用您的函数,然后使用古老而可靠的apply-macro-to-region-lines。
除此之外,我认为你可以在几行elisp中编写循环,以实现你所要求的功能。如果你想要更加高级一些,甚至可以提示用户输入函数名称。我认为这是一个对elisp很好的练习,如果你想自己尝试的话,我可以提供一些指南。

3

我同意@Lindydancer的答案,并且我还想补充一点,可能有更简单的方法来实现你的目标。例如,使用内置函数delete-matching-lines。:-)


-1

您可以随时将源代码复制到apply-macro-to-region-lines并进行调整,以调用传入的函数,从而创建自己的版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接