Як експортувати заголовки верхнього рівня в буфер OR-режиму до окремих файлів?


17

Як кожне заголовок org-modeбуфера верхнього рівня можна експортувати в окремий файл, названий за значенням відповідного CUSTOM_ID+ (санізованого) заголовка?

Скажімо, буфер містить:

* Title of Heading 1
  :PROPERTIES:
  :CUSTOM_ID: fibrillogenesis
  :END:
  Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  

** Sub-Heading
   Nullam rutrum.

* Another Title for Heading 2
  :PROPERTIES:
  :CUSTOM_ID: mitochondrion
  :END:
  Mauris mollis tincidunt felis.  Sed bibendum.

Кінцевим результатом буде каталог, що містить два файли, по одному для кожного з двох заголовків верхнього рівня, з форматом, обраним у час експорту (HTML, LaTeX тощо) із наступними назвами файлів та вмістом:

  1. Ім'я першого експортованого заголовка: fibrillogenesis-title-of-heading-1.[ext]

    Експортований вміст, що відповідає первинному заголовку першого рівня:

    * Title of Heading 1
      :PROPERTIES:
      :CUSTOM_ID: fibrillogenesis
      :END:
      Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  
    
    ** Sub-Heading 
       Nullam rutrum.
    
  2. Ім'я другого експортованого заголовка: mitochondrion-another-title-for-heading-2.[ext]

    Експортований вміст, що відповідає початковому другому заголовку верхнього рівня:

    * Another Title for Heading 2
    :PROPERTIES:
    :CUSTOM_ID: mitochondrion
    :END:
    Mauris mollis tincidunt felis.  Sed bibendum. 
    

Буду дуже вдячний за будь-яку підказку, напрямок, псевдокод або (краще) реальний код.

Відповіді:


27

Наступна команда дозволяє вибирати бек-енд, а потім експортувати кожне піддерево верхнього рівня в окремий файл:

(defun org-export-all (backend)
  "Export all subtrees that are *not* tagged with :noexport: to
separate files.

Note that subtrees must have the :EXPORT_FILE_NAME: property set
to a unique value for this to work properly."
  (interactive "sEnter backend: ")
  (let ((fn (cond ((equal backend "html") 'org-html-export-to-html)
                  ((equal backend "latex") 'org-latex-export-to-latex)
                  ((equal backend "pdf") 'org-latex-export-to-pdf))))
    (save-excursion
      (set-mark (point-min))
      (goto-char (point-max))
      (org-map-entries (lambda () (funcall fn nil t)) "-noexport" 'region-start-level))))

На даний момент підтримується експорт HTML ( html), LaTeX ( latex) та PDF ( pdf). Ви можете додати підтримку для більшої кількості зворотних версій, додавши до них більше пропозицій cond.

Як говориться в docstring, для кожного піддерева потрібно встановити :EXPORT_FILE_NAME:властивість на ім'я файлу, до якого потрібно експортувати. (Інші параметри див. Нижче).

Автоматичне генерування імені файлу експорту з тексту заголовка

Якщо ви не хочете додавати :EXPORT_FILE_NAME:властивості до кожного заголовка верхнього рівня, ви можете змінити, org-export-allщоб автоматично генерувати ім’я файлу, наприклад, текст заголовка, тимчасово встановлений :EXPORT_FILE_NAME:під час експорту:

(defun org-export-all (backend)
  "Export all subtrees that are *not* tagged with :noexport: to
separate files.

Subtrees that do not have the :EXPORT_FILE_NAME: property set
are exported to a filename derived from the headline text."
  (interactive "sEnter backend: ")
  (let ((fn (cond ((equal backend "html") 'org-html-export-to-html)
                  ((equal backend "latex") 'org-latex-export-to-latex)
                  ((equal backend "pdf") 'org-latex-export-to-pdf)))
        (modifiedp (buffer-modified-p)))
    (save-excursion
      (set-mark (point-min))
      (goto-char (point-max))
      (org-map-entries
       (lambda ()
         (let ((export-file (org-entry-get (point) "EXPORT_FILE_NAME")))
           (unless export-file
             (org-set-property
              "EXPORT_FILE_NAME"
              (replace-regexp-in-string " " "_" (nth 4 (org-heading-components)))))
           (funcall fn nil t)
           (unless export-file (org-delete-property "EXPORT_FILE_NAME"))
           (set-buffer-modified-p modifiedp)))
       "-noexport" 'region-start-level))))

Ця функція генерує імпорт файлу експорту, замінюючи пробіли на "_" у тексті заголовка. Якщо ви хочете генерувати ім'я файлу іншим способом, змініть replace-regexp-in-stringпідставку на те, що вам подобається.

Створення :EXPORT_FILE_NAME:при налаштуванні:CUSTOM_ID:

Дотримуючись наведених нижче порад, org-set-propertyавтоматично встановлюється відповідне значення :EXPORT_FILE_NAME:при встановленні :CUSTOM_ID::

(defadvice org-set-property (after set-export-file-name
                                   (property value) activate compile)
  (when (equal org-last-set-property "CUSTOM_ID")
    (let ((export-file-name
           (concat (org-entry-get nil "CUSTOM_ID")
                   "-"
                   (replace-regexp-in-string " " "-" (downcase (org-get-heading t t))))))
      (org-entry-put nil "EXPORT_FILE_NAME" export-file-name))))

Зауважте, що це не додасть розширення файлу до значення, :EXPORT_FILE_NAME:але це не має значення, оскільки при експорті до конкретного бек-енду org-mode автоматично вибере правильне розширення для файлів, що випливають .


Додаткова інформація

Оновлення існуючих підкреслень оптом

Якщо у вас є велика кількість існуючих підрядів, для яких потрібно встановити :EXPORT_FILE_NAME:властивість, ви можете використовувати макрос клавіатури . Поставте точку на першому піддереві, потім виконайте наступне:

  • F3

    ... для початку запису.

  • C-c C-x p CUSTOM_ID RET RET

    ... зробити Emacs :EXPORT_FILE_NAME:на основі :CUSTOM_ID:.

  • C-c C-f

    ... щоб перейти до наступного заголовка верхнього рівня.

  • F4

    ... припинити запис.

Щоб повторити макрос для наступного піддерева, натисніть F4. Щоб повторити макрос для всіх інших підрядів, натисніть M-0 F4(це нуль).

Збереження макросів для майбутніх сеансів

За замовчуванням макроси клавіатури не зберігаються протягом сеансів. Щоб зберегти макрос у своєму init-файлі для подальшого використання, зробіть це:

  1. Назвіть макрос:

    M-x name-last-kbd-macro RET org-set-export-file-name RET

  2. Знайдіть свій файл init та перейдіть до місця, де ви хочете вставити макрос.

  3. Вставте макрос:

    M-x insert-kbd-macro RET org-set-export-file-name RET

    Emacs вставить наступний код у точку:

    (fset 'org-set-export-file-name
       "\C-c\C-xpCUSTOM_ID\C-m\C-m\C-c\C-f")

    Якщо ви косити досить сильно, ви можете бачити, що другий аргумент fsetмістить послідовність клавіш, які ви натискали, коли ви записували макрос :)

  4. (Необов’язково) Для найкращих результатів, можливо, ви захочете прив’язати org-set-export-file-nameдо клавіші:

    (define-key org-mode-map (kbd "<f6>") 'org-set-export-file-name)
  5. Зберегти.


1
Приємно. Чи можете ви підказати мені, як програмно встановити :EXPORT_FILE_NAME:властивість :CUSTOM_ID:+heading-title-lowercasedдля кожного заголовка?
gsl

1
@gsl Ви можете порадити org-set-propertyавтоматично генерувати :EXPORT_FILE_NAME:властивість під час налаштування :CUSTOM_ID:.
itsjeyd

1
Дякую за пораду! Я не так вільно elisp, але спробую. Мені потрібно дізнатися, як захопити заголовок кожного заголовка, замінити пробіл білим пробілом, поставити на малі регістри, додати цей санізований рядок :CUSTOM_ID:і, нарешті, встановити властивість org.
gsl

1
@gsl Я додав defadviceдо мого відповіді , який автоматично встановлює :EXPORT_FILE_NAME:на <custom-id>-<heading>при установці :CUSTOM_ID:.
itsjeyd

1
Дуже дякую, я багато чого навчився з вашим кодом. Якщо у вас уже є org-modeфайл із CUSTOM_IDвстановленим s, як можна запустити код для встановлення "EXPORT_FILE_NAME"? Не буде нових вставок. Я здогадуюсь defadvice, не буде працювати? Чи є петельний інструмент для переміщення всіх заголовків верхнього рівня та застосування коду до них?
gsl
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.