💾 Archived View for spline-online.ru › blog › 20241123-org_mode_to_gemini.gmi captured on 2024-12-17 at 10:04:07. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

Org-mode в Gemini

2024-11-23 13:47:32

Я уже достаточно долгое время пользуюсь Emacs. Естественно, я активно пользуюсь его org-mode, который применяю как в работе, так и в личной жизни. Это отличный инструмент для ведения заметок, списков дел, планов, базы знаний и отслеживания рабочих задач. А если к нему добавить расширение deft, то всё это дополняется удобным нечётким поиском и навигацией. Впрочем, сегодня я буду писать не об этом.

Org-mode позволяет экспортировать документы в большое количество форматов: от plain text до html, LaTeX и даже odt. Помимо встроенных экспортеров есть сторонние, позволяющие экспортировать документы, например, в gemitext. Последнее и стало для меня причиной пересмотреть ведение своей капсулы.

Итак, нам понадобится расширение ox-gemini, являющееся экспортером из org-mode в gemtext. Установить его можно любым удобным для вас способом. Я предпочитаю использовать встроенный менеджер пакетов, в которой я добавил репозиторий melpa. Сделать это можно так:

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/"))
(package-initialize)

После чего можно установить пакет командой `M-x package-install RET ox-gemini`.

Дальше займёмся настройкой. ox-gemini базируется на встроенном экспортере ox-ascii, что накладывает некоторые отпечатки на вид выходного документа. Так, все ссылки, встречающиеся в тексте он приводит к формату `[DESCRIPTION]`, а сами ссылки располагает в конце секции документа. Так как я не предполагаю встраивать ссылки в текст, а располагаю каждую на отдельной строке примерно так, как это будет в gemtext, мне такое поведение не нравится. Поэтому пришлось это исправить.

Для начала, стоит отключить размещение ссылок в конце секций:

(setq org-ascii-links-to-notes nil)

Теперь нужно разобраться с преобразованием ссылок непосредственно в тексте. В экспортерах за это отвечает функция вида `org-FORMAT-link`. Переопределим её:

(defun org-gemini-link (link desc _info)
  (let ((add (replace-regexp-in-string "^file:" "" (org-element-property :raw-link link))))
    (setq add (replace-regexp-in-string ".org$" ".gmi" add))
    (format "=> %s %s" add desc)))

Помимо переопределения непосредственно выходного формата мы производим небольшие преобразования: убираем схему `file:` и заменяем расширение `.org` на `.gmi`, чтобы иметь локально весь контент связанным и в формате org-mode, а на выходе получить связанный контент в формате gemtext.

Уже неплохо, но ссылка не завершается переводом строки. Всё дело в том, как экспортер форматирует параграфы. Он убирает одиночные переводы строк, что не позволяет расположить ссылки не разных строках в рамках одного параграфа. За форматирование параграфа отвечает функция `org-gemini-link`. Заставим её просто пробрасывать контент как есть:

(defun org-gemini-paragraph (_paragraph contents _info)
  contents)

Остался ещё небольшой недостаток для вставок кода в строках. По умолчанию экспортер завершает любой код переводом строки. Для блоков кода это не является проблемой, но внутри строк от этого лучше избавиться:

(defun org-gemini-code-inline (input _contents info)
  (format "`%s`" (string-replace "\n" "" (org-export-format-code-default input info))))

Всё. Теперь мы можем отредактировать документ и экспортировать его в gemtext с помощью комбинации клавиш `C-e g f`.

Но экспортировать по одному документу достаточно неудобно. Давайте настроим публикацию всей капсулы одной командой.

Org-mode имеет интерактивную функцию `org-publish` предназначенную именно для этого. Однако, публикация требует некоторых настроек. Приведу пример из своего конфигурационного файла, прокомментировав опции:

(setq org-publish-project-alist
      '(("gemini" ;; идентификатор директории
         :base-directory "~/docs/gemini/" ;; путь ко входной директории
         :base-extension "org" ;; расширения, обрабатываемые экспортером, можно указать любые файлы или вообще убрать, тогда будут перенесены файлы указанных расширений или все
         :publishing-function org-gemini-publish-to-gemini ;; Указание функции публикации. Зависит от выбранного экспортера
         :publishing-directory "~/docs/gemini_pub") ;; Путь к выходной директории
        ("blog"
         :base-directory "~/docs/gemini/blog/"
         :base-extension "org"
         :publishing-function org-gemini-publish-to-gemini
         :publishing-directory "~/docs/gemini_pub/blog")
      ("capsule" :components ("gemini" "blog" "instead" "instead-files")))) ;; Здесь мы собираем все директории в одну кучку, чтобы публиковать их по одному идентификатору

Теперь, при выполнении команды `M-x org-publish RET capsule` мы получим экспортированную капсулу по указанному выходному пути и нам останется только залить её на сервер.

Впрочем, это можно поручить самому emacs'у. Зачем делать что-либо руками, если можно это автоматизировать? Для этого достаточно переопределить параметр `:publishing-directory` следующим образом:

:publishing-directory "/ssh:user@host:~/gemini"

Не забудьте указать свои имя пользователя, хост и путь :)

Удачи!