警告:不加思索地使用,以下可能让您的机器瘫痪。我会在最后添加一些更具体的警告,但要小心!
下面代码的基本思想是解析Org模式文件的缓冲区,以得到缓冲区的解析树:这是由org-element-parse-buffer完成的。然后,我们可以使用org-element-map 遍历解析树并选择only 类型为link 的节点,同时对每个节点应用一个函数。我们应用的函数get-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))
请注意,我只保留 http 和 https 链接:您可能需要添加额外的类型。
这对于获得您想要的东西已经大有帮助。其实如果你用上面两个函数加载文件,你可以在下面的示例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" 并将其映射到链接列表,生成一个新的 URL 列表。然后我们将函数browse-url(由emacs提供)映射到结果列表中,然后我们观察浏览器将它们全部打开。
警告:
如果文件中有成百上千个链接,那么您将在浏览器中创建成百上千个选项卡。你确定你的机器可以承受吗?
如果您的链接指向大对象,则会给您的系统带来另一种内存压力。你确定你的机器可以承受吗?
-
如果您的 Org 模式缓冲区很大,那么 org-element-parse-buffer 可能需要 LONG 时间来处理它。而且,虽然有缓存机制,但是因为bug,默认是没有开启的,所以每次执行函数都会从头开始解析缓冲区AGAIN。
每次执行函数时,都会在浏览器中打开新选项卡。
针对 cmets 中的问题进行编辑:
Q1:“visit-all-http-links 打开文件中的所有 URL。我最初的问题是,是否可以只打开当前 org-mode 章节中找到的 URL。”
A1:如果您保证该区域在语法上是正确的 Org 模式(例如标题及其内容的集合),则只做一个区域有点困难,但可能。您只需将该区域写入临时缓冲区,然后执行我在临时缓冲区而不是原始缓冲区上所做的操作。
这是使用问题 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:“每次我使用您的示例 URL 执行您的函数时,都会以不同的顺序打开 URL - 是否可以按照在 org 文件中找到的顺序打开 URL?”
A2:链接是按照它们在文件中出现的顺序确定性地找到的。但是当你调用browse-url 的那一刻,所有的赌注都没有了,因为 URL 现在属于浏览器,它会尝试在单独的选项卡中打开它接收到的每个 URL,并使用单独的线程 - 在换句话说,异步。您可以尝试在通话之间引入延迟,但不能保证:
(defun visit-url(url)
(browse-url)
(sit-for 1 t))
然后在visit-all-urls 中使用visit-url 而不是browse-url。