如何在 Emacs 缓冲区中同时打开多个 URL?

How to open multiple URLs at the same time in an Emacs buffer?

我将 Emacs 编辑器与 org-mode 和 evil-mode 结合使用,主要用于文本处理和文档编制。通常有一个主题,其中有几个不同的网站 URL 所属。

示例:我有一个关于如何安装 Emacs 的文本片段:

*** install emacs

emacs - I want to try org-mode. What's the shortest path from zero to typing? - Stack Overflow


Index of /gnu/emacs/windows/emacs-26
http://ftp.gnu.org/gnu/emacs/windows/emacs-26/emacs-26.3-x86_64.zip

Installation target:
file://C:\Lupo_Pensuite\MyApps\emacs

How to
file://C:\Lupo_Pensuite\MyDocs\howto.txt

是否可以 select 在我的默认网络浏览器中打开区域和所有 URL? link 文件正在被 Windows 资源管理器打开?文本文件是用关联的编辑器打开的吗?

甚至更好:emacs 知道 a.m。文本片段实际上是一个组织模式章节。而且无论光标在该章节中的哪个位置,诸如 M-x open-all-links-in-chapter 之类的东西都是...打开当前章节中提到的所有 links。

优先级 1:emacs/org-mode/evil-mode 中是否已经存在类似的东西?

优先级 2:是否有您知道的 elisp 函数可以实现此用例?

环境:Cygwin Windows 10,emacs 26.3,org-mode 9.1.9

警告:不慎使用,以下可能让您的机器崩溃。我会在最后添加一些更具体的警告,但要小心!

下面代码的基本思想是解析Org模式文件的缓冲区,以获得缓冲区的解析树:由org-element-parse-buffer完成。然后,我们可以使用 org-element-map 来遍历解析树和 select 只有 类型 link 的节点,在我们走的时候对每个节点应用一个函数。我们应用的函数 get-link 遍历 link 节点的内容,提取类型和路径并返回这两者的列表。到目前为止,它是这样的:

(defun get-link (x)
  (let* ((link (cadr x))
         (type (plist-get link :type))
         (path (plist-get link :path)))
   (if (or (string= type "http") (string= type "https"))
     (list type path))))

(defun visit-all-http-links ()
  (interactive)
  (let* ((parse-tree (org-element-parse-buffer))
         (links (org-element-map parse-tree 'link #'get-link)))
    links))

请注意,我只保留 httphttps links:您可能需要添加额外的类型。

这已经大大有助于您获得想要的东西。事实上,如果你用上面的两个函数加载文件,你可以在下面的示例 Org 模式文件上尝试:

* foo
** foo 1
http://www.google.com
https://redhat.com
* bar
** bar 2
[[https://gnome.org][Gnome]] is a FLOSS project. So is Fedora: https://fedoraproject.org.


* Code
#+begin_src emacs-lisp :results value verbatim :wrap example
(visit-all-http-links)
#+end_src

#+RESULTS:
#+begin_example
(("http" "//www.google.com") ("https" "//redhat.com") ("https" "//gnome.org") ("https" "//fedoraproject.com"))
#+end_example

并使用 C-c C-c 评估源块,您会得到显示的结果。

现在我们需要做的就是将结果列表中的每个 (TYPE PATH) 对转换为真正的 URL 然后访问它 - 这是代码的最终版本:


(defun get-link (x)
  "Assuming x is a LINK node in an Org mode parse tree,
   return a list consisting of its type (e.g. \"http\")
   and its path."
  (let* ((link (cadr x))
         (type (plist-get link :type))
         (path (plist-get link :path)))
   (if (or (string= type "http") (string= type "https"))
     (list type path))))

(defun format-url (x)
  "Take a (TYPE PATH) list and return a proper URL. Note
   the following works for http- and https-type links, but
   might need modification for other types."
  (format "%s:%s" (nth 0 x) (nth 1 x)))

(defun visit-all-http-links ()
  (interactive)
  (let* ((parse-tree (org-element-parse-buffer))
         (links (org-element-map parse-tree 'link #'get-link)))
    (mapcar #'browse-url (mapcar #'format-url links))))

我们添加一个函数 format-url 来执行此操作:("http" "//example.com") --> "http://example.com" 并将其映射到 links 列表,生成新的 URLS 列表。然后我们将函数 browse-url(由 emacs 提供)映射到结果列表中,我们会看到浏览器将它们全部打开。

警告:

  • 如果文件中有数百或数千个 link,那么您将在浏览器中创建数百或数千个选项卡。你确定你的机器可以接受吗?

  • 如果您的 link 指向大的 objects,那将会给您的系统带来另一种内存压力。你确定你的机器可以接受吗?

  • 如果您的 Org 模式缓冲区很大,那么 org-element-parse-buffer 可能需要 LONG 的时间来处理它。而且,虽然有缓存机制,但是因为bug默认是不开启的,所以每次执行函数都会从头开始解析缓冲区AGAIN

  • 每次执行该函数时,您将在浏览器中打开 NEW 选项卡。

针对评论中的问题进行编辑:

Q1:"visit-all-http-links opens all URLs in the file. My original question was, whether it is possible to open only the URLs which are being found in the current org-mode chapter."

A1:如果您保证该区域在语法上是正确的 Org 模式(例如 collection 标题及其内容),则只做一个区域有点困难但也是可能的。您只需将该区域写入临时缓冲区,然后执行我在临时缓冲区而不是原始缓冲区上所做的操作。 这是使用问题 2 中的 visit-url 函数修改后的代码:

(defun visit-all-http-links-in-region (beg end)
  (interactive "r")
  (let ((s (buffer-substring beg end)))
    (with-temp-buffer
      (set-buffer (current-buffer))
      (insert s)
      (let* ((parse-tree (org-element-parse-buffer))
             (links (org-element-map parse-tree 'link #'get-link)))
        (mapcar #'visit-url (mapcar #'format-url links))))))

(defun visit-all-http-links ()
  (interactive)
  (visit-all-http-links-in-region (point-min) (point-max)))

测试很简单

Q2:"Every time I execute your function with your example URLs, the URLs are being opened with a different sequence - is it possible to open the URLs in that very sequence which is found in the org file?"

A2:link 是按照它们在文件中出现的顺序确定性地找到的。但是在你调用 browse-url 的那一刻,所有的赌注都关闭了,因为 URL 现在属于浏览器,它将尝试打开它在单独的选项卡中收到的每个 URL 和 使用一个单独的线程 - 换句话说异步。您可以尝试在调用之间引入延迟,但不能保证:

(defun visit-url(url)
   (browse-url)
   (sit-for 1 t))

然后在visit-all-urls中使用visit-url代替browse-url

事实证明,org-mode 已经 built-in!

今天我正在浏览 org-mode 的文档,想知道 究竟 C-c C-o 是如何工作的。该组合键正在调用 emacs org-mode 函数“org-open-at-point”。 org-open-at-point 正在打开光标(在 emacs 中:点)所在的 URL。

现在,如果在 标题 上按下 C-c C-o,则 all URL 位于其下方标题已打开!这正是我从一开始就要求的。非常感谢 NickD 的建设性贡献!

这里是帮助原文:

When point is on a headline, display a list of every link in the entry, so it is possible to pick one, or all, of them.