Comment exporter des en-têtes de niveau supérieur du tampon en mode org vers des fichiers séparés?

17

Comment chaque en-tête de niveau supérieur d'un org-modetampon peut-il être exporté vers un fichier distinct nommé d'après la valeur du titre CUSTOM_ID+ (filtré) correspondant?

Disons qu'un tampon contient:

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

Le résultat final serait un répertoire contenant deux fichiers, un pour chacun des deux en-têtes de niveau supérieur, avec le format choisi au moment de l'exportation (HTML, LaTeX, etc.), avec les noms de fichiers et le contenu suivants:

  1. Nom de fichier du premier titre exporté: fibrillogenesis-title-of-heading-1.[ext]

    Contenu exporté, correspondant au premier titre de premier niveau d'origine:

    * Title of Heading 1
      :PROPERTIES:
      :CUSTOM_ID: fibrillogenesis
      :END:
      Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  
    
    ** Sub-Heading 
       Nullam rutrum.
    
  2. Nom de fichier du deuxième titre exporté: mitochondrion-another-title-for-heading-2.[ext]

    Contenu exporté, correspondant au deuxième titre de niveau supérieur d'origine:

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

Je serais très reconnaissant pour tout indice, direction, pseudocode ou (meilleur) code réel.

gsl
la source

Réponses:

27

La commande suivante vous permet de choisir un serveur principal, puis d'exporter chaque sous-arbre de niveau supérieur dans un fichier distinct:

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

Cela prend actuellement en charge l' exportation HTML ( html), LaTeX ( latex) et PDF ( pdf). Vous pouvez ajouter la prise en charge de plusieurs back-ends en ajoutant plus de clauses à cond.

Comme le dit la docstring, pour chaque sous-arbre, vous devez définir la :EXPORT_FILE_NAME:propriété sur le nom de fichier vers lequel vous souhaitez l'exporter. (Voir ci-dessous pour d'autres options.)

Génération automatique du nom du fichier d'exportation à partir du texte de l'en-tête

Si vous ne souhaitez pas ajouter de :EXPORT_FILE_NAME:propriétés à chaque en-tête de niveau supérieur, vous pouvez le modifier org-export-allpour générer automatiquement le nom de fichier à partir, par exemple, du texte de l'en-tête, en définissant temporairement :EXPORT_FILE_NAME:pendant l'exportation:

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

Cette fonction génère le nom du fichier d'exportation en remplaçant les espaces par "_" dans le texte du titre. Si vous souhaitez générer le nom de fichier d'une autre manière, changez le replace-regexp-in-stringsexp en ce que vous voulez.

Génération :EXPORT_FILE_NAME:lors du paramétrage:CUSTOM_ID:

Avec les conseils suivants, org-set-propertydéfinira automatiquement une valeur appropriée :EXPORT_FILE_NAME:lorsque vous définissez :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))))

Notez que cela n'ajoutera pas d'extension de fichier à la valeur de :EXPORT_FILE_NAME:mais cela n'a pas d'importance car lors de l'exportation vers un back-end spécifique, org-mode choisira automatiquement l'extension correcte pour les fichiers résultants .


Information additionnelle

Mise à jour groupée des sous-arbres existants

Si vous avez un grand nombre de sous-arborescences existantes pour lesquelles vous devez définir la :EXPORT_FILE_NAME:propriété, vous pouvez utiliser une macro de clavier . Positionnez le point sur le premier sous-arbre, puis procédez comme suit:

  • F3

    ... pour commencer l'enregistrement.

  • C-c C-x p CUSTOM_ID RET RET

    ... pour que Emacs soit :EXPORT_FILE_NAME:basé sur :CUSTOM_ID:.

  • C-c C-f

    ... pour passer au titre supérieur suivant.

  • F4

    ... pour arrêter l'enregistrement.

Pour répéter la macro pour la sous-arborescence suivante, appuyez sur F4. Pour répéter la macro pour tous les sous-arbres restants, appuyez sur M-0 F4(c'est un zéro).

Enregistrement de macros pour les sessions futures

Par défaut, les macros de clavier ne sont pas enregistrées entre les sessions. Pour stocker la macro dans votre fichier init pour une utilisation ultérieure, procédez comme suit:

  1. Nommez la macro:

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

  2. Trouvez votre fichier init et déplacez-vous à un endroit où vous souhaitez insérer la macro.

  3. Insérez la macro:

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

    Emacs insérera le code suivant au point:

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

    Si vous plissez les yeux assez fort, vous pouvez voir que le deuxième argument fsetcontient la séquence de touches sur laquelle vous avez appuyé lorsque vous avez enregistré la macro :)

  4. (Facultatif) Pour de meilleurs résultats, vous souhaiterez peut-être vous lier org-set-export-file-nameà une clé:

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

itsjeyd
la source
1
Agréable. Pourriez-vous me donner un indice sur la façon de définir la :EXPORT_FILE_NAME:propriété par programme :CUSTOM_ID:+heading-title-lowercasedpour chaque en-tête?
gsl
1
@gsl Vous pouvez conseiller org-set-propertyde générer automatiquement la :EXPORT_FILE_NAME:propriété lorsque vous définissez :CUSTOM_ID:.
itsjeyd
1
Merci pour le conseil! Je ne suis pas à l'aise avec elisp, mais je vais essayer. J'ai besoin de savoir comment capturer le titre de chaque titre, remplacer l'espace blanc par un tiret, mettre en minuscules, ajouter cette chaîne filtrée :CUSTOM_ID:et enfin définir une propriété d'organisation.
gsl
1
@gsl J'ai ajouté un defadviceà ma réponse qui règle automatiquement :EXPORT_FILE_NAME:à <custom-id>-<heading>lorsque vous définissez :CUSTOM_ID:.
itsjeyd
1
Merci beaucoup, j'ai beaucoup appris avec votre code. Si l'on avait déjà un org-modefichier avec CUSTOM_IDs set, comment pourrait-on exécuter le code pour définir "EXPORT_FILE_NAME"? Il n'y aurait pas de nouvelles insertions. Je suppose que defadvicecela ne fonctionnerait pas? Existe-t-il une fonction de boucle pour parcourir toutes les en-têtes de niveau supérieur et leur appliquer le code?
gsl