Jak wyeksportować nagłówki najwyższego poziomu bufora trybu org do oddzielnych plików?

17

Jak można org-modewyeksportować każdy nagłówek najwyższego poziomu bufora do osobnego pliku nazwanego na podstawie wartości odpowiedniego CUSTOM_ID+ (odkażonego) tytułu?

Powiedzmy, że bufor zawiera:

* 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.

Ostatecznym rezultatem byłby katalog zawierający dwa pliki, po jednym dla każdego z dwóch nagłówków najwyższego poziomu, w formacie wybranym podczas eksportu (HTML, LaTeX itp.), Z następującymi nazwami plików i zawartością:

  1. Nazwa pliku pierwszego wyeksportowanego nagłówka: fibrillogenesis-title-of-heading-1.[ext]

    Wyeksportowana treść, odpowiadająca pierwotnemu pierwszemu nagłówkowi najwyższego poziomu:

    * Title of Heading 1
      :PROPERTIES:
      :CUSTOM_ID: fibrillogenesis
      :END:
      Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  
    
    ** Sub-Heading 
       Nullam rutrum.
    
  2. Nazwa drugiego eksportowanego nagłówka: mitochondrion-another-title-for-heading-2.[ext]

    Wyeksportowana treść, odpowiadająca pierwotnemu drugiemu nagłówkowi najwyższego poziomu:

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

Byłbym bardzo wdzięczny za każdą wskazówkę, kierunek, pseudokod lub (lepszy) prawdziwy kod.

gsl
źródło

Odpowiedzi:

27

Następujące polecenie pozwala wybrać zaplecze, a następnie eksportuje każde poddrzewo najwyższego poziomu do osobnego pliku:

(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))))

Obsługuje to obecnie eksport HTML ( html), LaTeX ( latex) i PDF ( pdf). Możesz dodać obsługę większej liczby back-endów, dodając więcej klauzul do cond.

Jak głosi dokument, dla każdego poddrzewa należy ustawić :EXPORT_FILE_NAME:właściwość na nazwę pliku, do którego ma zostać wyeksportowany. (Zobacz inne opcje poniżej).

Automatyczne generowanie nazwy pliku eksportu z tekstu nagłówka

Jeśli nie chcesz dodawać :EXPORT_FILE_NAME:właściwości do każdego nagłówka najwyższego poziomu, możesz zmodyfikować, org-export-allaby automatycznie wygenerować nazwę pliku np. Z tekstu nagłówka, ustawiając tymczasowo :EXPORT_FILE_NAME:podczas eksportu:

(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))))

Ta funkcja generuje nazwę pliku eksportu, zastępując spacje znakiem „_” w tekście nagłówka. Jeśli chcesz wygenerować nazwę pliku w inny sposób, zmień replace-regexp-in-stringpłeć na dowolną.

Generowanie :EXPORT_FILE_NAME:podczas ustawiania:CUSTOM_ID:

Z następującymi wskazówkami org-set-propertyautomatycznie ustawi odpowiednią wartość :EXPORT_FILE_NAME:podczas ustawiania :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))))

Zauważ, że nie doda to rozszerzenia pliku do wartości, :EXPORT_FILE_NAME:ale to nie ma znaczenia, ponieważ podczas eksportowania do określonego zaplecza org-mode automatycznie wybierze prawidłowe rozszerzenie dla plików wynikowych .


Dodatkowe informacje

Zbiorcza aktualizacja istniejących poddrzewa

Jeśli masz wiele istniejących poddrzew, dla których musisz ustawić :EXPORT_FILE_NAME:właściwość, możesz użyć makra klawiatury . Ustaw punkt na pierwszym poddrzewie, a następnie wykonaj następujące czynności:

  • F3

    ... aby rozpocząć nagrywanie.

  • C-c C-x p CUSTOM_ID RET RET

    ... aby ustawić Emacsa :EXPORT_FILE_NAME:na podstawie :CUSTOM_ID:.

  • C-c C-f

    ... aby przejść do następnego nagłówka najwyższego poziomu.

  • F4

    ... aby zatrzymać nagrywanie.

Aby powtórzyć makro dla następnego poddrzewa, naciśnij F4. Aby powtórzyć makro dla wszystkich pozostałych poddrzew, naciśnij M-0 F4(to zero).

Zapisywanie makr na przyszłe sesje

Domyślnie makra klawiaturowe nie są zapisywane między sesjami. Aby zapisać makro w pliku inicjującym do późniejszego wykorzystania, wykonaj następujące czynności:

  1. Nazwij makro:

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

  2. Znajdź plik init i przejdź do miejsca, w którym chcesz wstawić makro.

  3. Wstaw makro:

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

    Emacs wstawi następujący kod w punkcie:

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

    Jeśli zmrużysz wystarczająco mocno, zobaczysz, że drugi argument fsetzawiera sekwencję klawiszy naciśniętych podczas rejestrowania makra :)

  4. (Opcjonalnie) Aby uzyskać najlepsze wyniki, możesz powiązać org-set-export-file-namez kluczem:

    (define-key org-mode-map (kbd "<f6>") 'org-set-export-file-name)
  5. Zapisać.

itsjeyd
źródło
1
Ładny. Czy mógłbyś mi podpowiedzieć, jak programowo ustawić :EXPORT_FILE_NAME:właściwość :CUSTOM_ID:+heading-title-lowercaseddla każdego nagłówka?
gsl
1
@gsl Możesz ustawić org-set-propertyautomatyczne generowanie :EXPORT_FILE_NAME:właściwości po ustawieniu :CUSTOM_ID:.
itsjeyd
1
Dziękuję za radę! Nie jestem tak biegły elisp, ale spróbuję. Muszę dowiedzieć się, jak uchwycić tytuł każdego nagłówka, zastąpić białe znaki myślnikiem, umieścić małe litery, dodać ten odkażony ciąg :CUSTOM_ID:i wreszcie ustawić właściwość org.
gsl
1
@gsl Dodałem a defadvicedo mojej odpowiedzi, która automatycznie ustawia się :EXPORT_FILE_NAME:na <custom-id>-<heading>kiedy ustawiasz :CUSTOM_ID:.
itsjeyd
1
Dziękuję bardzo, wiele się nauczyłem z twojego kodu. Jeśli ktoś miałby już org-modeplik z CUSTOM_IDustawieniem s, jak można uruchomić kod, aby ustawić „EXPORT_FILE_NAME”? Nie będzie nowych wstawek. Zgaduję, defadviceże nie zadziała? Czy istnieje funkcja zapętlania, która umożliwia przeglądanie wszystkich nagłówków najwyższego poziomu i stosowanie do nich kodu?
gsl