Как открыть несколько URL-адресов одновременно в буфере Emacs? - PullRequest
1 голос
/ 05 мая 2020

Я использую редактор Emacs вместе с org-mode и evil-mode в основном для обработки текста и документации. Часто встречается топи c, где принадлежат несколько разных URL-адресов веб-сайтов.

Пример: у меня есть фрагмент текста о том, как установить Emacs:

Можно ли выбрать регион и все URL-адреса открываются в моем веб-браузере по умолчанию? А ссылку на файл открывает Windows проводник? И текстовый файл открывается в соответствующем редакторе?

Или даже лучше: emacs знает, что текстовый фрагмент am на самом деле является главой в организационном режиме. И независимо от того, где в этой главе расположен курсор, что-то вроде Mx open-all-links-in-chapter ... открывает все упомянутые ссылки в текущей главе.

Prio 1: есть ли что-то подобное уже существует в emacs / org-mode / evil-mode?

Prio 2: есть ли функция elisp, которую вы знаете, которая может достичь этого варианта использования?

Enviroment: Cygwin под Windows 10 , emacs 26.3, org-mode 9.1.9

1 Ответ

1 голос
/ 06 мая 2020

Предупреждение: использование без раздумий следующее может поставить вашу машину на колени. Я добавлю еще несколько 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...