【问题标题】:Is there an apply-command-to-each-line-in-region in emacs?emacs 中是否有一个 apply-command-to-each-line-in-region ?
【发布时间】:2015-08-02 01:24:11
【问题描述】:

我有一堆链接保存在一个 orgmode 文件中,比如说...

http://www.stackoverflow.com
http://www.google.com
http://www.github.com

我可以通过将光标放在链接上并执行C-c C-o 来打开每个链接,它会方便地弹出我的默认浏览器并在选项卡中打开该链接。

现在假设我有 20 个这样的链接。有没有一种方便的方法可以将这样的函数应用于选定区域内的每一行,而无需记录显式宏?

我想它看起来像......

Select region
M-x foreach-in-region
Keystrokes to apply to each line: C-c C-o

这仅适用于已经定义的函数。我想没有的方式会是……

with cursor on first line of link
F3 # to start record macro
C-c C-o 
down arrow
F4
Select region (omitting the first line, since that's now already opened in my browser)
C-x C-k r

这存在吗?如果不是,我怎么会口齿不清?

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    您应该为一行录制宏,然后使用apply-macro-to-region-lines 对区域中的所有行执行它。 C-x C-k r

    或者,您可以使用多个光标在每一行上创建一个光标,然后 C-c C-o 打开所有光标。 multiple-cursors 会随着时间的推移改变你的使用模式,如果你给它一个机会的话。

    【讨论】:

    • C-c C-o 是多光标中的默认键绑定吗?最好将调用的 defun 命名为 imo。
    【解决方案2】:
    (defun do-lines (fun &optional start end)
      "Invoke function FUN on the text of each line from START to END."
      (interactive
       (let ((fn   (intern (completing-read "Function: " obarray 'functionp t))))
         (if (use-region-p)
             (list fn (region-beginning) (region-end))
           (list fn (point-min) (point-max)))))
      (save-excursion
        (goto-char start)
        (while (< (point) end)
          (funcall fun (buffer-substring (line-beginning-position) (line-end-position)))
          (forward-line 1))))
    

    评论后更新 --

    现在听起来您不想输入函数名称而是按一个键,并将绑定到该键的命令应用于区域(或缓冲区)中的每一行。

    类似下面的东西可以做到这一点。但是,请注意,命令通常具有特定的行为 wrt 行。例如,如果您要按下键 C-k (kill-lines),那么它已经在它杀死的每一行之后向前移动。因为do-lines 不知道您将调用什么样的函数(命令),所以它在每次调用后前进到下一行。对于像kill-lines 这样的命令,这会做错事:它最终会前进两行,而不是一行,从而跳过行。 IOW,请注意 do-lines 的代码无法补偿它调用的特定函数可能会执行的操作可能与您的期望不符。相反,它会按照它所说的去做。

    (defun do-lines (command &optional start end)
      "Invoke COMMAND on the text of each line from START to END."
      (interactive
       (let* ((key  (read-key-sequence-vector "Hit key sequence: "))
              (cmd  (lookup-key global-map key t)))
         (when (numberp cmd) (error "Not a valid key sequence"))
         (unless (commandp cmd) (error "Key `%s' is not defined" (key-description key)))
         (if (use-region-p)
             (list cmd (region-beginning) (region-end))
           (list cmd (point-min) (point-max)))))
      (setq start  (copy-marker start)
            end    (copy-marker end))
      (save-excursion
        (goto-char start)
        (while (< (point) end)
          (funcall command (buffer-substring (line-beginning-position) (line-end-position)))
          (forward-line 1))))
    

    【讨论】:

    • 当我在我的选择上运行它时,我得到 "C-c C-o" 没有定义,虽然是为单行定义的。
    • 不知道你的意思。 C-c C-o 是什么?你在哪里定义它,你期望它做什么?当您调用do-lines(无论如何调用它- 使用键或M-x)时,它会提示您将该函数应用于每一行。按照现在的定义,你需要给它一个函数名,而不仅仅是敲击一个键。
    • 在我的例子中,我想调用的函数不需要任何参数,所以我将 funcall 行更改为 (funcall command) 或 (funcall fun),具体取决于您使用的版本。像魅力一样工作!
    【解决方案3】:

    在某些情况下,您可以使用Emacs RepeatingC-x z 后跟更多的`z'。我试图评论区域中的所有行,它对我的​​用例很有效。

    命令 C-x z (repeat) 提供了另一种重复 Emacs 的方法 命令多次

    要多次重复该命令,请输入额外的 z:每个 z 重复该命令一次

    【讨论】:

      【解决方案4】:

      本着 TIMTOWTDI[1] 的精神,我将指出一种适用于某些情况的技术,包括 OP 中的情况。

      如果您希望在一行以空格分隔的字符串(如 URL)上运行外部命令:

      1. 选择地区
      2. 调用M-| (Alt+Shift+\, shell-command-on-region)
      3. 使用 xargs 作为所需命令的前缀命令(例如,xdg-openx-www-browser

      例如,为第 3 步输入的完整命令可能是:

      xargs -n1 xdg-open
      

      -n1 开关导致xargs 一次打开调用给定程序的一个参数;它将为每个输入运行一次程序。如果命令可以一次处理多个参数,则可以省略 -n1。例如,我有一个 web 命令可以打开多个 URL 作为参数,所以只需 xargs web 即可。

      这种方法的主要好处是,它适用于任何符合 POSIX 标准的东西,而无需事先做任何事情。缺点包括,它只适用于外部命令,并且需要xargs(默认情况下并非每个操作系统都包含)。


      [1] 方法不止一种,最初来自 Perl,但在其他地方很有用。

      【讨论】:

        猜你喜欢
        • 2011-09-25
        • 2010-12-05
        • 2022-12-26
        • 1970-01-01
        • 2017-01-29
        • 2022-12-02
        • 2022-12-01
        • 2022-12-02
        • 1970-01-01
        相关资源
        最近更新 更多