Предупреждение: использование без раздумий следующее может поставить вашу машину на колени. Я добавлю еще несколько c предупреждений в конце, но будьте осторожны!
Основная идея c кода ниже состоит в том, чтобы проанализировать буфер файла режима организации, чтобы получить дерево синтаксического анализа буфера: это делает org-element-parse-buffer
. Затем мы можем использовать org-element-map
для обхода дерева синтаксического анализа и выбора только узлов типа link
, применяя функцию к каждому из них, как мы go. Применяемая нами функция 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
: вы можете добавить дополнительные типы.
Это уже имеет большое значение чтобы получить то, что вы хотите. Фактически, если вы загрузите файл с двумя функциями, указанными выше, вы можете попробовать его в следующем образце файла режима организации:
* 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-element-parse-buffer
может занять ДЛИННЫЙ время обработать его. Более того, несмотря на наличие механизма кэширования, он не включен по умолчанию из-за ошибок, поэтому каждый раз, когда вы выполняете функцию, вы собираетесь анализировать буфер СНОВА с нуля.
Каждый раз, когда вы выполняете функцию, вы собираетесь открывать NEW вкладок в вашем браузере.
EDIT в ответ на вопросы в комментариях:
Q1: «visit-all-http-links открывает все URL-адреса в файле. Мой первоначальный вопрос заключался в том, можно ли открыть только те URL-адреса, которые находятся в текущем org-mode chapter. "
A1: Сделать только регион немного сложнее, но возможно, если вы гарантируете, что регион является синтаксически правильным режимом Org (например, набор заголовков и их содержимого). Вы просто записываете регион во временный буфер, а затем делаете то же самое, что и я, с временным буфером вместо оригинала. Вот измененный код с использованием функции visit-url
из Вопроса 2:
(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-адреса в той самой последовательности, которая находится в орг-файле? "
A2: Ссылки обнаруживаются детерминированно в том порядке, в котором они встречаются в файле. Но в тот момент, когда вы вызываете browse-url
, все ставки отменяются, потому что URL-адрес теперь принадлежит браузеру, который будет пытаться открыть каждый URL-адрес, который он получает, в отдельной вкладке и , используя отдельный поток - в другом слова асинхронно. Вы можете попробовать ввести задержку между вызовами, но нет никаких гарантий:
(defun visit-url(url)
(browse-url)
(sit-for 1 t))
, а затем использовать visit-url
вместо browse-url
в visit-all-urls
.