¿Cómo exportar encabezados de nivel superior del búfer de modo org para separar archivos?

17

¿Cómo se org-modepuede exportar cada encabezado de nivel superior de un búfer a un archivo separado con el nombre del valor del CUSTOM_IDtítulo + (desinfectado) correspondiente?

Digamos que un búfer contiene:

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

El resultado final sería un directorio que contiene dos archivos, uno para cada uno de los dos encabezados de nivel superior, con el formato elegido en el momento de la exportación (HTML, LaTeX, etc.), con los siguientes nombres de archivos y contenido:

  1. Nombre de archivo del primer encabezado exportado: fibrillogenesis-title-of-heading-1.[ext]

    Contenido exportado, correspondiente al primer encabezado de primer nivel original:

    * Title of Heading 1
      :PROPERTIES:
      :CUSTOM_ID: fibrillogenesis
      :END:
      Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  
    
    ** Sub-Heading 
       Nullam rutrum.
    
  2. Nombre de archivo del segundo encabezado exportado: mitochondrion-another-title-for-heading-2.[ext]

    Contenido exportado, correspondiente al segundo título original de nivel superior:

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

Estaría muy agradecido por cualquier pista, dirección, pseudocódigo o (mejor) código real.

gsl
fuente

Respuestas:

27

El siguiente comando le permite elegir un back-end y luego exporta cada subárbol de nivel superior a un archivo separado:

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

Actualmente es compatible con la exportación de HTML ( html), LaTeX ( latex) y PDF ( pdf). Puede agregar soporte para más back-end agregando más cláusulas a cond.

Como dice la cadena de documentación, para cada subárbol debe establecer la :EXPORT_FILE_NAME:propiedad con el nombre de archivo al que desea que se exporte. (Ver abajo para otras opciones).

Generar automáticamente el nombre del archivo de exportación a partir del texto del encabezado

Si no desea agregar :EXPORT_FILE_NAME:propiedades a cada encabezado de nivel superior, puede modificarlo org-export-allpara generar el nombre de archivo automáticamente, por ejemplo, desde el texto del encabezado, configurando temporalmente :EXPORT_FILE_NAME:durante la exportación:

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

Esta función genera el nombre de archivo de exportación reemplazando espacios con "_" en el texto del título. Si desea generar el nombre de archivo de otra manera, cambie el replace-regexp-in-stringsexp a lo que quiera.

Generando :EXPORT_FILE_NAME:al configurar:CUSTOM_ID:

Con el siguiente consejo, org-set-propertyestablecerá automáticamente un valor apropiado para :EXPORT_FILE_NAME:cuando establezca :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))))

Tenga en cuenta que esto no agregará una extensión de archivo al valor de :EXPORT_FILE_NAME:pero eso no importa porque al exportar a un back-end específico, org-mode elegirá automáticamente la extensión correcta para los archivos resultantes .


Información Adicional

Actualización de subárboles existentes a granel

Si tiene una gran cantidad de subárboles existentes para los que necesita establecer la :EXPORT_FILE_NAME:propiedad, puede usar una macro de teclado . Coloque el punto en el primer subárbol, luego haga lo siguiente:

  • F3

    ... para comenzar a grabar.

  • C-c C-x p CUSTOM_ID RET RET

    ... para hacer Emacs :EXPORT_FILE_NAME:basado en :CUSTOM_ID:.

  • C-c C-f

    ... para pasar al siguiente título de nivel superior.

  • F4

    ... para detener la grabación.

Para repetir la macro para el siguiente subárbol, presione F4. Para repetir la macro para todos los subárboles restantes, presione M-0 F4(eso es un cero).

Guardar macros para futuras sesiones

Por defecto, las macros de teclado no se guardan en las sesiones. Para almacenar la macro en su archivo de inicio para su uso posterior, haga lo siguiente:

  1. Nombra la macro:

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

  2. Busque su archivo init y muévase a un lugar donde le gustaría insertar la macro.

  3. Insertar la macro:

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

    Emacs insertará el siguiente código en el punto:

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

    Si entrecierra los ojos lo suficiente, puede ver que el segundo argumento fsetcontiene la secuencia de teclas que presionó cuando grabó la macro :)

  4. (Opcional) Para obtener mejores resultados, es posible que desee vincular org-set-export-file-namea una clave:

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

itsjeyd
fuente
1
Agradable. ¿Podría darme una pista sobre cómo establecer mediante programación la :EXPORT_FILE_NAME:propiedad :CUSTOM_ID:+heading-title-lowercasedpara cada encabezado?
gsl
1
@gsl Podría aconsejar org-set-propertygenerar automáticamente la :EXPORT_FILE_NAME:propiedad cuando establezca :CUSTOM_ID:.
itsjeyd
1
¡Gracias por el consejo! No soy tan fluido elisp, pero lo intentaré. Necesito descubrir cómo capturar el título de cada encabezado, sustituir el espacio en blanco con un guión, ponerlo en minúsculas, agregar esa cadena desinfectada :CUSTOM_ID:y finalmente establecer una propiedad de organización.
gsl
1
@gsl añadí una defadvicea mi respuesta que automáticamente conjuntos :EXPORT_FILE_NAME:a <custom-id>-<heading>cuando se establece :CUSTOM_ID:.
itsjeyd
1
Muchas gracias, he aprendido mucho con su código. Si ya hubiera un org-modearchivo con CUSTOM_IDs configurado, ¿cómo podría ejecutar el código para configurar "EXPORT_FILE_NAME"? No habría nuevas inserciones. Supongo defadviceque no funcionaría? ¿Existe una función de bucle para recorrer todos los encabezados de nivel superior y aplicarles el código?
gsl