Arquivo Org Tangle contendo # + INCLUDE diretivas e vários alvos tangle

Oct 18 2020

Contexto

Estou usando org-babel-tanglepara gerar minha configuração a partir de um arquivo Org config.org. Recentemente, fiz uma limpeza por

  1. envio config.orgpara vários arquivos Org config/*.org;
  2. substitua o conteúdo de config.orgpor várias #+INCLUDE: config/*.orgdiretivas.

Para ilustrar um pouco, a árvore de diretórios é a seguinte:

config/
|______ A.org
|______ B.org
|______ C.org
|
config.org

Onde

## config.org
#+INCLUDE: config/A.org
#+INCLUDE: config/B.org
#+INCLUDE: config/C.org
...

e

## [ABC].org
#+BEGIN_SRC emacs-lisp :tangle target1.el
;; elisp code
#+END_SRC

#+BEGIN_SRC emacs-lisp :tangle target2.el
;; elisp code
#+END_SRC
...

Problema e tentativa

No entanto, encontrei o problema que org-babel-tanglenão trata das #+INCLUDEdiretivas. Então, eu sigo a ideia deste post que consiste em

  1. exportar config.orgpara um arquivo Org config-export.orgcom org-export-to-file;
  2. org-babel-tangleo arquivo Org exportado config-export.orgpara emaranhar destinos.

Essa abordagem substitui as várias #+INCLUDEdiretivas de config.orgpelo conteúdo de config/*.org, mas todas as opções de emaranhado são apagadas . Ou seja, o exportado se config-export.orgparece com isto (todos os nomes de arquivo de destino emacs-lisp emaranhados são perdidos):

## config-export.org
#+BEGIN_SRC emacs-lisp
;; elisp code for target1.el
#+END_SRC

#+BEGIN_SRC emacs-lisp
;; elisp code for target2.el
#+END_SRC
...

Pergunta

Como criar org-babel-tangleum arquivo Org com #+INCLUDEdiretivas conforme pretendido?

( ou seja, (1) inclui todos os arquivos org (preservando :tangle target.el) e (2) org-babel-tangletodo o arquivo org.)

Questão relacionada

Uma questão semelhante foi levantada na lista de e-mails do modo Org.

Respostas

2 NickD Oct 19 2020 at 23:26

Não sei como fazer isso sem alterar o código (pode ser possível com, org-babel-pre-tangle-hookmas não parecia nada simples, então não tentei fazer isso). Mas assim que você aceita as alterações de código, não parece tão ruim.

A maneira mais simples possível que eu poderia pensar era emular o org-babel-tangleque org-export-asestá fazendo o WRT incluir arquivos. Um teste simples (semelhante ao que você descreveu acima) foi bem-sucedido facilmente (mas veja as advertências no final), então, se você quiser tentar replicar a mudança, incluo o patch abaixo.

O patch em si pareceria grande, mas isso é apenas porque estou pegando todo o código org-babel-tanglee colocando-o em outra camada, o que muda o recuo e essa é a maior parte da mudança. Ignorando as mudanças de espaço em branco, a mudança "real" é muito menor: eu peguei o patch abaixo com a git diff -bfim de ignorar os espaços em branco. Você pode então ver que é muito pequeno: nós apenas incluímos quase todo o corpo de org-babel-tanglein (org-export-with-buffer-copy ...), para que possamos fazer transformações no texto em um buffer temporário e não atrapalhar o original e então adicionar mais uma transformação para processar as #+INCLUDE:diretivas, antes o buffer resultante é então emaranhado:

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index b74b3fa0c..5e6eebf63 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -206,6 +206,9 @@ export file for all source blocks.  Optional argument LANG-RE can
 be used to limit the exported source code blocks by languages
 matching a regular expression."
   (interactive "P")
+  (org-export-with-buffer-copy
+   (org-export-expand-include-keyword)
+
    (run-hooks 'org-babel-pre-tangle-hook)
    ;; Possibly Restrict the buffer to the current code block
    (save-restriction
@@ -306,7 +309,7 @@ matching a regular expression."
     (mapc (lambda (pair)
         (when (cdr pair) (set-file-modes (car pair) (cdr pair))))
           path-collector)
-   (mapcar #'car path-collector)))))
+    (mapcar #'car path-collector))))))
 
 (defun org-babel-tangle-clean ()
   "Remove comments inserted by `org-babel-tangle'.

Isso produz os resultados esperados WRT os arquivos emaranhados, eu acho, mas você deve verificar para ter certeza de que faz a coisa certa no seu caso: meus testes são testes de brinquedo, então eles podem perder situações complicadas que podem surgir em seus testes do "mundo real" .

Há um problema que eu ainda não entendo: o config.orgbuffer em si é alterado em meus testes, apesar do org-export-with-copy-buffer, então no final do emaranhado eu tenho que desfazer a alteração com C-x ue salvá-lo. Provavelmente porque não entendo o que org-export-with-copy-bufferrealmente está acontecendo , mas ainda não verifiquei esse código.

OTOH, se isso for resolvido e todos os testes passarem, podemos propor isso como uma melhoria para a lista de e-mail do modo Org e deixar esse problema (de 2010!) Para trás.

EDIT: Eu não vejo nenhum problema com org-babel-tangle-file- ele chama org-babel-tangleembaixo, então em teoria ele deve fazer a coisa (quase) certa e testá-lo com um exemplo simples funciona bem para mim. Talvez você possa postar um (pequeno) exemplo que lhe dê problemas ao editar sua pergunta?

Também estou testando a seguinte solução alternativa para contornar o problema de config.orgser alterado:

#+begin_src emacs-lisp
(copy-file "./config.org.orig" "./config.org")
(org-babel-tangle-file "./config.org")
(delete-file "./config.org")
#+end_src

Feio, mas parece funcionar (exceto que eu tenho que responder à pergunta "alterado no disco").

2 Melioratus Oct 26 2020 at 09:30

Método 1

Método manual usando atalhos de teclado do modo org padrão

Configurar

  1. Adicione Orgà Org Babel Load Languagesconfiguração e, em seguida, aplique e salve a nova configuração.

  2. Adicione uma #+EXPORT_FILE_NAME:palavra-chave próximo ao topo de config.org.

    por exemplo

    #+EXPORT_FILE_NAME: temp.org
    
  3. Adicione uma #+PROPERTY: header-args:org :results drawer replacepalavra-chave próximo ao topo de config.org.

    por exemplo

    #+PROPERTY: header-args:org :results drawer replace
    
  4. Atualize #+INCLUDE:para incluir a src orgsintaxe.

    por exemplo

    #+INCLUDE: config/A.org src org
    #+INCLUDE: config/B.org src org
    #+INCLUDE: config/C.org src org
    
  5. Adicione :eval nevercabeçalho a cada um dos SRCblocos que serão emaranhados dentro dos config/*.orgarquivos incluídos .

    por exemplo

    #+BEGIN_SRC elisp :tangle tangle1.el :eval never 
      ;; Code goes here
    #+END_SRC
    

Etapas de execução manual

  1. Abra config.orgno emacs.

    O config.orgarquivo deve ser semelhante ao exemplo abaixo:

    #+EXPORT_FILE_NAME: temp.org
    #+PROPERTY: header-args:org :results drawer replace 
    
    #+INCLUDE: config/A.org src org
    #+INCLUDE: config/B.org src org
    #+INCLUDE: config/C.org src org
    
  2. Exporte config.orgusando C-c C-e O vacorde chave. Isso criará um novo temp.orgarquivo e abrirá no emacs.

    O temp.orgarquivo deve ser semelhante ao exemplo abaixo:

    #+export_file_name: temp.org
    #+property: header-args:org :results drawer replace
    
    #+begin_src org
      ,#+BEGIN_SRC elisp :tangle tangle1.el :eval never 
        ;; Code goes here
      ,#+END_SRC
    #+end_src
    #+begin_src org
      ,#+BEGIN_SRC elisp :tangle tangle2.el :eval never 
        ;; Code goes here
      ,#+END_SRC
    #+end_src
    #+begin_src org
      ,#+BEGIN_SRC elisp :tangle tangle3.el :eval never 
        ;; Code goes here
      ,#+END_SRC
    #+end_src
    
  3. Execute todos os blocos no acorde temp.orgusando a C-c C-v C-bchave.

    O temp.orgarquivo deve ser semelhante ao exemplo abaixo:

    #+export_file_name: temp.org
    #+property: header-args:org :results drawer replace
    
    #+begin_src org
      ,#+BEGIN_SRC elisp :tangle tangle1.el :eval never 
        ;; Code goes here
      ,#+END_SRC
    #+end_src
    
    #+RESULTS:
    :results:
    #+BEGIN_SRC elisp :tangle tangle1.el :eval never 
      ;; Code goes here
    #+END_SRC
    :end:
    
    #+begin_src org
      ,#+BEGIN_SRC elisp :tangle tangle2.el :eval never 
        ;; Code goes here
      ,#+END_SRC
    #+end_src
    
    #+RESULTS:
    :results:
    #+BEGIN_SRC elisp :tangle tangle2.el :eval never 
      ;; Code goes here
    #+END_SRC
    :end:
    
    #+begin_src org
      ,#+BEGIN_SRC elisp :tangle tangle3.el :eval never 
        ;; Code goes here
      ,#+END_SRC
    #+end_src
    
    #+RESULTS:
    :results:
    #+BEGIN_SRC elisp :tangle tangle3.el :eval never 
      ;; Code goes here
    #+END_SRC
    :end:
    
  4. Execute o emaranhado no acorde da tecla temp.orgusing C-c C-v C-t. Isso confundirá os SRCblocos importados dos config/*.orgarquivos.

    Isso criará os arquivos emaranhados semelhantes aos arquivos listados abaixo:

    config.org
    tangle1.el
    tangle2.el
    tangle3.el
    temp.org
    
    ./config:
    A.org
    B.org
    C.org
    

Esta resposta foi testada usando:
versão emacs: GNU Emacs 27.1
org-mode version: 9.3.7